/**
  @file sys_usw_nexthop_api.c

  @date 2009-11-11

  @version v2.0

  The file contains all nexthop API function for upper layer module
 */
/****************************************************************************
 *
* Header Files
*
****************************************************************************/
#include "ctc_const.h"
#include "ctc_error.h"
#include "ctc_linklist.h"
#include "ctc_nexthop.h"
#include "ctc_packet.h"
#include "sys_usw_common.h"
#include "sys_usw_aps.h"
#include "sys_usw_port_api.h"
#include "sys_usw_l3if.h"
#include "sys_usw_qos_api.h"
#include "sys_usw_nexthop.h"
#include "sys_usw_nexthop_hw.h"
#include "sys_usw_opf.h"
#include "sys_usw_internal_port.h"
#include "sys_usw_wb_nh.h"
#include "sys_usw_register.h"

#include "drv_api.h"

/****************************************************************************
 *
* Defines and Macros
*
*****************************************************************************/

/****************************************************************************
 *
* Global and Declaration
*
*****************************************************************************/
sys_usw_nh_api_master_t* p_usw_nh_api_master[CTC_MAX_LOCAL_CHIP_NUM_PP] = {NULL};

/****************************************************************************
 *
* Function
*
*****************************************************************************/

STATIC int32
_sys_usw_nh_brguc_port_hash_make(void* p_data)
{
    return ctc_hash_caculate(sizeof(uint32), p_data);
}

STATIC bool
_sys_usw_nh_brguc_port_hash_cmp(sys_hbnh_brguc_node_info_t* p_data0, sys_hbnh_brguc_node_info_t* p_data1)
{
    if (!p_data0 || !p_data1)
    {
        return TRUE;
    }

    if (p_data0->gport == p_data1->gport)
    {
        return TRUE;
    }

    return FALSE;
}
/**
 @brief This function is to initialize nexthop API data,
 */
int32
sys_usw_nh_api_init(uint8 lchip, ctc_nh_global_cfg_t* nh_cfg)
{

    int32    ret = 0;

    if (p_usw_nh_api_master[lchip])
    {
        return CTC_E_NONE;
    }

    if (SYS_VCHIP_PP_IS_NOT_BASE(lchip))
    {
        p_usw_nh_api_master[lchip] = p_usw_nh_api_master[SYS_PP_BASE(lchip)];
        g_usw_nh_master[lchip] = g_usw_nh_master[SYS_PP_BASE(lchip)];
        return CTC_E_NONE;
    }

    p_usw_nh_api_master[lchip] = (sys_usw_nh_api_master_t*)mem_malloc(MEM_NEXTHOP_MODULE, (sizeof(sys_usw_nh_api_master_t)));
    if (NULL == p_usw_nh_api_master[lchip])
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_usw_nh_api_master[lchip], 0, (sizeof(sys_usw_nh_api_master_t)));
    /*1. Bridge Ucast Data init*/
    if (NULL != p_usw_nh_api_master[lchip])
    {
        SYS_NH_CREAT_LOCK(p_usw_nh_api_master[lchip]->brguc_info.brguc_mutex);
        SYS_NH_CREAT_LOCK(p_usw_nh_api_master[lchip]->p_mutex);
    }
    else
    {
        mem_free(p_usw_nh_api_master[lchip]);
        p_usw_nh_api_master[lchip] = NULL;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
			return CTC_E_NO_MEMORY;

    }

    p_usw_nh_api_master[lchip]->brguc_info.brguc_hash = ctc_hash_create(MCHIP_CAP(SYS_CAP_PORT_NUM_PER_CHIP)*2/CTC_HASH_256_BLOCK_SIZE,
                                                    CTC_HASH_256_BLOCK_SIZE,
                                                    (hash_key_fn)_sys_usw_nh_brguc_port_hash_make,
                                                    (hash_cmp_fn)_sys_usw_nh_brguc_port_hash_cmp);
    if (NULL == p_usw_nh_api_master[lchip]->brguc_info.brguc_hash)
    {
        sal_mutex_destroy(p_usw_nh_api_master[lchip]->brguc_info.brguc_mutex);
        sal_mutex_destroy(p_usw_nh_api_master[lchip]->p_mutex);
        mem_free(p_usw_nh_api_master[lchip]);
        p_usw_nh_api_master[lchip] = NULL;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        return CTC_E_NO_MEMORY;
    }

    ret = (sys_usw_nh_init(lchip, nh_cfg));
    if (ret)
    {
        sys_usw_nh_deinit(lchip);
        sal_mutex_destroy(p_usw_nh_api_master[lchip]->brguc_info.brguc_mutex);
        sal_mutex_destroy(p_usw_nh_api_master[lchip]->p_mutex);
        mem_free(p_usw_nh_api_master[lchip]);
        p_usw_nh_api_master[lchip] = NULL;
        return ret;
    }

    /*2. Create default nexthop*/
    if (!(CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING) )
    {
        /*wb reloading have recovered*/
        CTC_ERROR_RETURN(_sys_usw_misc_nh_create(lchip, SYS_NH_RESOLVED_NHID_FOR_DROP, SYS_NH_TYPE_DROP));
        CTC_ERROR_RETURN(_sys_usw_misc_nh_create(lchip, SYS_NH_RESOLVED_NHID_FOR_TOCPU, SYS_NH_TYPE_TOCPU));
        if ((DRV_IS_TMM(lchip) || DRV_IS_TMG(lchip)))
        {
            sys_nh_param_iloop_t nh_param;
            ctc_loopback_nexthop_param_t ctc_nh_param;
            sal_memset(&nh_param, 0, sizeof(sys_nh_param_iloop_t));
            sal_memset(&ctc_nh_param, 0, sizeof(ctc_loopback_nexthop_param_t));
            nh_param.hdr.nh_param_type = SYS_NH_TYPE_ILOOP;
            nh_param.hdr.is_internal_nh = TRUE;
            nh_param.p_iloop_param = &ctc_nh_param;
            CTC_ERROR_RETURN(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)));
            g_usw_nh_master[lchip]->rsv_iloop_nh = nh_param.hdr.nhid;
            sal_memset(&nh_param, 0, sizeof(sys_nh_param_iloop_t));
            sal_memset(&ctc_nh_param, 0, sizeof(ctc_loopback_nexthop_param_t));
            nh_param.hdr.nh_param_type = SYS_NH_TYPE_ILOOP;
            nh_param.hdr.is_internal_nh = TRUE;
            ctc_nh_param.lpbk_lport = 1;
            nh_param.p_iloop_param = &ctc_nh_param;
            CTC_ERROR_RETURN(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)));
        }
    }
    sys_usw_nh_rsv_drop_ecmp_member(lchip);
    sys_usw_mchip_set_feature_en(lchip,CTC_FEATURE_NEXTHOP);
    return CTC_E_NONE;
}


STATIC int32
_sys_usw_nh_api_free_node_data(void* node_data, void* user_data)
{
    mem_free(node_data);

    return CTC_E_NONE;
}

int32
sys_usw_nh_api_deinit(uint8 lchip)
{
    LCHIP_CHECK(lchip);
    if (NULL == p_usw_nh_api_master[lchip])
    {
        return CTC_E_NONE;
    }
    if (SYS_VCHIP_PP_IS_NOT_BASE(lchip) && (0 == sys_usw_ftm_get_nh_pp_en(lchip)))
    {
        p_usw_nh_api_master[lchip] = NULL;
        g_usw_nh_master[lchip] = NULL;
        return CTC_E_NONE;
    }

    sys_usw_nh_deinit(lchip);

    /*free bridge uc vector*/
    ctc_hash_free2(p_usw_nh_api_master[lchip]->brguc_info.brguc_hash, (hash_traversal_fn)_sys_usw_nh_api_free_node_data, NULL);

    sal_mutex_destroy(p_usw_nh_api_master[lchip]->brguc_info.brguc_mutex);
    sal_mutex_destroy(p_usw_nh_api_master[lchip]->p_mutex);
    mem_free(p_usw_nh_api_master[lchip]);

    return CTC_E_NONE;
}

/**
 @brief This function is to create normal bridge nexthop

 @param[in] gport, global port id

 @param[in] nh_type, nexthop type

 @return CTC_E_XXX
 */
int32
sys_usw_brguc_nh_create(uint8 lchip, uint32 gport, ctc_nh_param_brguc_sub_type_t nh_type)
{
    int32 ret = 0;
#ifdef WARMBOOT
    uint8 nh_cnt = 0;
#endif
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "gport = 0x%x , nh_type = %d\n", gport, nh_type);

    SYS_NH_INIT_CHECK;
    SYS_GLOBAL_PORT_CHECK(gport);

    if (nh_type == CTC_NH_PARAM_BRGUC_SUB_TYPE_UNTAGGED
        || nh_type == CTC_NH_PARAM_BRGUC_SUB_TYPE_RAW_PACKET_ELOG_CPU
        || nh_type == CTC_NH_PARAM_BRGUC_SUB_TYPE_SERVICE_QUEUE)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " API or some feature is not supported \n");
		return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_LOCK;

#ifdef WARMBOOT
    nh_cnt = (nh_type == CTC_NH_PARAM_BRGUC_SUB_TYPE_ALL)?2:1;
    if(CTC_WB_ENABLE(lchip) && SYS_GCHIP_IS_REMOTE(lchip, CTC_MAP_GPORT_TO_GCHIP(gport)))
    {
        if((p_usw_nh_api_master[lchip]->brguc_info.rchip_nh_cnt + nh_cnt) > 2*SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_RCHIP_PORT))
        {
            SYS_NH_UNLOCK;
            return CTC_E_NO_RESOURCE;
        }
    }
#endif

    if (((nh_type & CTC_NH_PARAM_BRGUC_SUB_TYPE_BASIC) != 0) || (nh_type == CTC_NH_PARAM_BRGUC_SUB_TYPE_ALL))
    {
        ret = (_sys_usw_brguc_nh_create_by_type(lchip, gport, SYS_NH_PARAM_BRGUC_SUB_TYPE_BASIC));
        if ((CTC_E_EXIST != ret) && (CTC_E_NONE != ret))
        {
            SYS_NH_UNLOCK;
            return ret;
        }
    }

    if (((nh_type & CTC_NH_PARAM_BRGUC_SUB_TYPE_BYPASS) != 0) || (nh_type == CTC_NH_PARAM_BRGUC_SUB_TYPE_ALL))
    {
        ret = (_sys_usw_brguc_nh_create_by_type(lchip, gport, SYS_NH_PARAM_BRGUC_SUB_TYPE_BYPASS));
        if ((CTC_E_EXIST != ret) && (CTC_E_NONE != ret))
        {
            SYS_NH_UNLOCK;
            return ret;
        }
    }
    #ifdef WARMBOOT
    if(CTC_WB_ENABLE(lchip) && SYS_GCHIP_IS_REMOTE(lchip, CTC_MAP_GPORT_TO_GCHIP(gport)))
    {
        p_usw_nh_api_master[lchip]->brguc_info.rchip_nh_cnt += nh_cnt;
    }
    #endif
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief This function is to delete normal bridge nexthop

 @param[in] gport, global port id

 @param[in] nh_type, nexthop type

 @return CTC_E_XXX
 */
int32
sys_usw_brguc_nh_delete(uint8 lchip, uint32 gport)
{

    sys_hbnh_brguc_node_info_t* p_brguc_node;
    sys_hbnh_brguc_node_info_t brguc_node_tmp;
    #ifdef WARMBOOT
    uint8 nh_cnt = 0;
    #endif
    int32 ret = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "gport = %d\n", gport);

    SYS_NH_INIT_CHECK;
    SYS_GLOBAL_PORT_CHECK(gport);

    SYS_NH_BRGUC_LOCK;

    brguc_node_tmp.gport = gport;
    p_brguc_node = ctc_hash_lookup(p_usw_nh_api_master[lchip]->brguc_info.brguc_hash, &brguc_node_tmp);
    if (NULL == p_brguc_node)
    {
        SYS_NH_BRGUC_UNLOCK;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " [Nexthop] Nexthop not exist \n");
		return CTC_E_NOT_EXIST;
    }

    SYS_NH_LOCK;
    if (p_brguc_node->nhid_brguc != SYS_NH_INVALID_NHID)
    {
        ret = (sys_usw_nh_api_delete(lchip, p_brguc_node->nhid_brguc, SYS_NH_TYPE_BRGUC));
        p_brguc_node->nhid_brguc = SYS_NH_INVALID_NHID;
        #ifdef WARMBOOT
        nh_cnt++;
        #endif
    }

    if (p_brguc_node->nhid_bypass != SYS_NH_INVALID_NHID)
    {
        ret = ret ? ret : (sys_usw_nh_api_delete(lchip, p_brguc_node->nhid_bypass, SYS_NH_TYPE_BRGUC));
        p_brguc_node->nhid_bypass = SYS_NH_INVALID_NHID;
        #ifdef WARMBOOT
        nh_cnt++;
        #endif
    }
    SYS_NH_UNLOCK;

    if ((p_brguc_node->nhid_bypass == SYS_NH_INVALID_NHID)
        && (p_brguc_node->nhid_brguc == SYS_NH_INVALID_NHID))
    {
        ctc_hash_remove(p_usw_nh_api_master[lchip]->brguc_info.brguc_hash, p_brguc_node);
        mem_free(p_brguc_node);
    }
    #ifdef WARMBOOT
    if(CTC_WB_ENABLE(lchip) && SYS_GCHIP_IS_REMOTE(lchip, CTC_MAP_GPORT_TO_GCHIP(gport)))
    {
        p_usw_nh_api_master[lchip]->brguc_info.rchip_nh_cnt-=nh_cnt;
    }
    #endif
    SYS_NH_BRGUC_UNLOCK;
    return ret;
}

#define __IN_CALLBACK__
/*
  These function may used in nexthop cb function, and be called again, so do not using lock by in_cb is set to TRUE
*/

STATIC int32
_sys_usw_nh_get_dsfwd_offset(uint8 lchip, uint32 nhid, uint32 *p_dsfwd_offset, uint8 in_cb, uint8 feature, uint8 is_dsfwd1)
{
    sys_nh_info_com_t* p_nhinfo_new = NULL;
    int32 ret = 0;
    uint8 need_update = 0;
    uint32 flag = is_dsfwd1? SYS_NH_INFO_FLAG_HAVE_DSFWD1 : SYS_NH_INFO_FLAG_HAVE_DSFWD;
    sys_nh_info_dsnh_t dsnh;
    uint8 updateAd = 0;

    sal_memset(&dsnh, 0, sizeof(sys_nh_info_dsnh_t));

    SYS_NH_INIT_CHECK;

    if (!in_cb)
    {
        SYS_NH_LOCK;
    }

    CTC_ERROR_GOTO(_sys_usw_nh_get_nhinfo(lchip, nhid, &dsnh), ret, error_proc1);

    if ((dsnh.nh_entry_flags & SYS_NH_INFO_FLAG_MCAST_PROFILE))
    {
        /*mcast profile do not support dsfwd*/
        ret = CTC_E_INVALID_PARAM;
        goto error_proc;
    }

    if (!CTC_FLAG_ISSET(dsnh.nh_entry_flags, flag)
        && (dsnh.nh_entry_type != SYS_NH_TYPE_ECMP)
    && !(dsnh.nh_entry_flags & SYS_NH_INFO_FLAG_HAVE_RSV_DSFWD))
    {
        sys_nh_param_com_t nh_param;

        sal_memset(&nh_param, 0, sizeof(sys_nh_param_com_t));
        nh_param.hdr.nhid = nhid;
        nh_param.hdr.nh_param_type = dsnh.nh_entry_type;
        nh_param.hdr.change_type  = SYS_NH_CHANGE_TYPE_ADD_DYNTBL;
        nh_param.hdr.is_dsfwd1 = is_dsfwd1;
        nh_param.hdr.have_dsfwd = 1;

        CTC_ERROR_GOTO(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), ret, error_proc);
        CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, (sys_nh_info_com_t**)&p_nhinfo_new), ret, error_proc);

        /*use new alloced dsfwd offset*/
        dsnh.dsfwd1_offset = p_nhinfo_new->hdr.dsfwd1_offset;
        dsnh.dsfwd_offset = p_nhinfo_new->hdr.dsfwd_offset;
        /*if nh have bind already, update old AD to use dsfwd, disable merge dsfwd mode*/
        need_update = 1;
    }

    if (p_nhinfo_new&&
        (!(p_nhinfo_new->hdr.nh_entry_flags & flag)
        && !(p_nhinfo_new->hdr.nh_entry_flags & SYS_NH_INFO_FLAG_HAVE_RSV_DSFWD)))
    {
        ret = CTC_E_INVALID_PARAM;
        need_update = 0;
        goto error_proc;
    }

    *p_dsfwd_offset = is_dsfwd1?dsnh.dsfwd1_offset : dsnh.dsfwd_offset;



error_proc:
     /*1. nexthop module to get dsfwd offset, needn't disable merge dsfwd. used for ecmp,
       2. already have dsfwd and bind feature is not zero, need to disable merge dsfwd. Such as, ipuc1->nh, ecmp->nh, ipuc2->nh
       3. Get dsfwd1 offset, needn't disable merge dsfwd */
    dsnh.need_lock = 1;   
    if ((!is_dsfwd1 && ((need_update && feature != CTC_FEATURE_NEXTHOP) || (!need_update && dsnh.bind_feature)))
        && (feature == dsnh.bind_feature) && (lchip == dsnh.bind_lchip))
    {
        dsnh.need_lock = 0;
        dsnh.merge_dsfwd  = 2;

        CTC_ERROR_RETURN(sys_usw_nh_merge_dsfwd_disable(lchip, nhid, feature));
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_COM, 1);
        updateAd = 1;
    }

error_proc1:
    if(!in_cb)
    {
        SYS_NH_UNLOCK;
    }

    if (updateAd && dsnh.updateAd)
    {
        dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
    }

    return ret;

}

int32
sys_usw_nh_get_dsfwd_offset(uint8 lchip, uint32 nhid, uint32 *p_dsfwd_offset, uint8 in_cb, uint8 feature)
{
  /* !!!!!lock process in _sys_usw_nh_get_dsfwd_offset */
  CTC_ERROR_RETURN(_sys_usw_nh_get_dsfwd_offset(lchip, nhid, p_dsfwd_offset, in_cb, feature, 0));
  return CTC_E_NONE;
}
int32
sys_usw_nh_get_dsfwd1_offset(uint8 lchip, uint32 nhid, uint32 *p_dsfwd_offset, uint8 in_cb, uint8 feature)
{
  /* !!!!!lock process in _sys_usw_nh_get_dsfwd_offset */
  CTC_ERROR_RETURN(_sys_usw_nh_get_dsfwd_offset(lchip, nhid, p_dsfwd_offset, in_cb, feature, DRV_FROM_AT(lchip)? 1:0));
  return CTC_E_NONE;
}


int32
sys_usw_nh_get_aps_working_path(uint8 lchip, uint32 nhid, uint32* gport, uint32* nexthop_ptr, bool* p_protect_en)
{
    bool protect_en = 0;
    uint16 next_group_id = 0;
    sys_nh_info_dsnh_t sys_nh_info;
    int32 ret = CTC_E_NONE;

    SYS_NH_INIT_CHECK;

    sal_memset(&sys_nh_info, 0, sizeof(sys_nh_info));
    sys_nh_info.protection_path = (p_protect_en && (*p_protect_en))?1:0;
    SYS_NH_LOCK;
    ret = (_sys_usw_nh_get_nhinfo(lchip, nhid, &sys_nh_info));
    SYS_NH_UNLOCK;
    if (ret)
    {
        return ret;
    }
    if (NULL == p_protect_en)
    {
        CTC_ERROR_RETURN(sys_usw_aps_get_protection(lchip, sys_nh_info.gport, &protect_en));
    }
    else
    {
        protect_en = *p_protect_en;
    }

    *nexthop_ptr = sys_nh_info.dsnh_offset;
    CTC_ERROR_RETURN(sys_usw_aps_get_next_group(lchip, sys_nh_info.gport, &next_group_id, (!protect_en)));
    if (CTC_MAX_UINT16_VALUE == next_group_id)/*no nexthop aps group*/
    {
        CTC_ERROR_RETURN(sys_usw_aps_get_bridge_path(lchip, sys_nh_info.gport, gport, (!protect_en)));
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_aps_get_protection(lchip, next_group_id, &protect_en));
        CTC_ERROR_RETURN(sys_usw_aps_get_bridge_path(lchip, next_group_id, gport, (!protect_en)));
    }

    return CTC_E_NONE;
}


int32
sys_usw_nh_get_nhinfo(uint8 lchip, uint32 nhid, sys_nh_info_dsnh_t* p_nhinfo, uint8 in_cb)
{
    int32 ret = 0;

    SYS_NH_INIT_CHECK;
    if(!in_cb)
    {
        SYS_NH_LOCK;
    }
    /*1. check dirty flag first*/
    ret = sys_usw_nh_check_dirty(lchip, nhid);
    ret = ret ? ret : _sys_usw_nh_get_nhinfo(lchip, nhid, p_nhinfo);
    if(!in_cb)
    {
        SYS_NH_UNLOCK;
    }

    if( p_nhinfo->nh_entry_type != SYS_NH_TYPE_MCAST  && p_nhinfo->is_mcast)
    {  /*aps nexthop and aps mpls used as ecmp member*/
        p_nhinfo->dsnh_offset = 0;
    }

    return ret;
}


int32
sys_usw_nh_get_reason_nhinfo(uint8 lchip, uint16 reason_id, uint32* nexthop_ptr,uint8* dsnh_8w)
{
    int32 ret = CTC_E_NONE;
    sys_cpu_reason_dest_info_t dest_info;
    sal_memset(&dest_info, 0, sizeof(dest_info));

    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    ret = sys_usw_cpu_reason_get_info(lchip, reason_id, &dest_info);
    ret = ret ? ret : _sys_usw_nh_get_reason_nhinfo(lchip, &dest_info, reason_id, nexthop_ptr, dsnh_8w);
    SYS_NH_UNLOCK;

    return ret;
}

int32
sys_usw_l2_get_ucast_nh(uint8 lchip, uint32 gport, ctc_nh_param_brguc_sub_type_t nh_type, uint32* nhid)
{
    int32 ret = CTC_E_NONE;
    sys_hbnh_brguc_node_info_t* p_brguc_nhid_info = NULL;
    sys_hbnh_brguc_node_info_t brguc_node_tmp;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "gport = %d\n", gport);

    SYS_NH_INIT_CHECK;
    SYS_GLOBAL_PORT_CHECK(gport);
    if (nh_type == CTC_NH_PARAM_BRGUC_SUB_TYPE_UNTAGGED
        || nh_type == CTC_NH_PARAM_BRGUC_SUB_TYPE_RAW_PACKET_ELOG_CPU
        || nh_type == CTC_NH_PARAM_BRGUC_SUB_TYPE_SERVICE_QUEUE)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " API or some feature is not supported \n");
		return CTC_E_NOT_SUPPORT;
    }


    SYS_NH_BRGUC_LOCK;
    brguc_node_tmp.gport = gport;
    p_brguc_nhid_info = ctc_hash_lookup(p_usw_nh_api_master[lchip]->brguc_info.brguc_hash, &brguc_node_tmp);
    if (NULL == p_brguc_nhid_info)
    {
        SYS_NH_BRGUC_UNLOCK;
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " [Nexthop] Nexthop not exist \n");
		return CTC_E_NOT_EXIST;
    }

    switch (nh_type)
    {
    case CTC_NH_PARAM_BRGUC_SUB_TYPE_BASIC:
        if (p_brguc_nhid_info->nhid_brguc != SYS_NH_INVALID_NHID)
        {
            *nhid = p_brguc_nhid_info->nhid_brguc;
        }
        else
        {
            ret  = CTC_E_NOT_EXIST;
        }

        break;

    case CTC_NH_PARAM_BRGUC_SUB_TYPE_BYPASS:
        if (p_brguc_nhid_info->nhid_bypass != SYS_NH_INVALID_NHID)
        {
            *nhid = p_brguc_nhid_info->nhid_bypass;
        }
        else
        {
            ret  = CTC_E_NOT_EXIST;
        }

        break;

    default:
        SYS_NH_BRGUC_UNLOCK;
        return CTC_E_INVALID_PARAM;
    }

    SYS_NH_BRGUC_UNLOCK;
    return ret;
}

int32
sys_usw_nh_get_mcast_member(uint8 lchip, uint32 nhid, ctc_nh_info_t* p_nh_info)
{
    sys_nh_info_com_t* p_com_db = NULL;
    sys_nh_info_mcast_t* p_mcast_db = NULL;
    int32 ret = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "\n%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;

    CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, &p_com_db), ret, error_proc);

    p_mcast_db = (sys_nh_info_mcast_t*)p_com_db;

    CTC_ERROR_GOTO(
        sys_usw_nh_get_mcast_member_info(lchip, p_mcast_db, p_nh_info), ret, error_proc);

error_proc:
    SYS_NH_UNLOCK;

    return ret;
}

/**
 @brief This function is to create egress vlan edit nexthop

 @param[in] nhid, nexthop id of this nexthop

 @param[in] gport, global port id

 @param[in] p_vlan_info, vlan edit information

 @param[in] dsnh_offset, nexthop offset of this nexthop

 @return CTC_E_XXX
 */
int32
sys_usw_egress_vlan_edit_nh_create(uint8 lchip, uint32 nhid, uint32 gport,
                                         ctc_vlan_egress_edit_info_t* p_vlan_info, uint32 dsnh_offset,
                                         ctc_vlan_edit_nh_param_t* p_nh_param)
{
    sys_nh_param_brguc_t nh_brg;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d, gport = %d, dsnh_offset = %d",
                   nhid, gport, dsnh_offset);

    SYS_NH_INIT_CHECK;
    SYS_GLOBAL_PORT_CHECK(gport);
    CTC_PTR_VALID_CHECK(p_vlan_info);
    if (CTC_FLAG_ISSET(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_CVID_VALID))
    {
        CTC_MAX_VALUE_CHECK(p_vlan_info->output_cvid, CTC_MAX_VLAN_ID);
    }

    if (CTC_FLAG_ISSET(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_SVID_VALID))
    {
        CTC_MAX_VALUE_CHECK(p_vlan_info->output_svid, CTC_MAX_VLAN_ID);
    }
    if(CTC_FLAG_ISSET(p_vlan_info->flag, CTC_VLAN_NH_MTU_CHECK_EN))
    {
        CTC_MAX_VALUE_CHECK(p_vlan_info->mtu_size, SYS_MTU_MAX_SIZE);
    }

    SYS_USW_CID_CHECK(lchip, p_nh_param->cid);

    if ((p_vlan_info->user_vlanptr > MCHIP_CAP(SYS_CAP_MAX_VLAN_PTR)) && (p_vlan_info->user_vlanptr != 0xFFFF) && (p_vlan_info->user_vlanptr != 0xFFFE))
    {
        return CTC_E_INVALID_PARAM;
    }
    if (p_nh_param->aps_en)
    {
        return CTC_E_NOT_SUPPORT;
    }

    CTC_ERROR_RETURN(sys_usw_nh_check_max_glb_nh_offset(lchip, dsnh_offset));
    sal_memset(&nh_brg, 0, sizeof(sys_nh_param_brguc_t));

    SYS_NH_LOCK;
    nh_brg.hdr.nh_param_type = SYS_NH_TYPE_BRGUC;
    nh_brg.hdr.is_internal_nh = FALSE;
    nh_brg.hdr.nhid = nhid;
    nh_brg.nh_sub_type = SYS_NH_PARAM_BRGUC_SUB_TYPE_VLAN_EDIT;
    nh_brg.gport = gport;
    nh_brg.p_vlan_edit_info = p_vlan_info;
    nh_brg.dsnh_offset = dsnh_offset;
    nh_brg.loop_nhid = p_vlan_info->loop_nhid;
    nh_brg.p_vlan_edit_nh_param = p_nh_param;

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_brg)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief This function is to delete egress vlan edit nexthop

 @param[in] nhid, nexthop id of this nexthop

 @return CTC_E_XXX
 */
int32
sys_usw_egress_vlan_edit_nh_delete(uint8 lchip, uint32 nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_BRGUC), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief This function is to create egress vlan edit nexthop

 @param[in] nhid, nexthop id of this nexthop

 @param[in] gport, global port id

 @param[in] p_vlan_info, vlan edit information

 @param[in] dsnh_offset, nexthop offset of this nexthop

 @return CTC_E_XXX
 */
int32
sys_usw_egress_vlan_edit_nh_update(uint8 lchip, uint32 nhid,
                                         ctc_vlan_egress_edit_info_t* p_egs_vlan_info,
                                         ctc_vlan_edit_nh_param_t* p_nh_param)
{
    sys_nh_param_brguc_t nh_brg;
    ctc_vlan_egress_edit_info_t* p_vlan_info = &p_nh_param->vlan_edit_info;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    p_vlan_info = (NULL == p_egs_vlan_info) ? (&p_nh_param->vlan_edit_info) : p_egs_vlan_info;
    CTC_PTR_VALID_CHECK(p_vlan_info);
    if (CTC_FLAG_ISSET(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_CVID_VALID))
    {
        CTC_MAX_VALUE_CHECK(p_vlan_info->output_cvid, CTC_MAX_VLAN_ID);
    }

    if (CTC_FLAG_ISSET(p_vlan_info->edit_flag, CTC_VLAN_EGRESS_EDIT_OUPUT_SVID_VALID))
    {
        CTC_MAX_VALUE_CHECK(p_vlan_info->output_svid, CTC_MAX_VLAN_ID);
    }

    if(CTC_FLAG_ISSET(p_vlan_info->flag, CTC_VLAN_NH_MTU_CHECK_EN))
    {
        CTC_MAX_VALUE_CHECK(p_vlan_info->mtu_size, SYS_MTU_MAX_SIZE);
    }

    SYS_USW_CID_CHECK(lchip, p_nh_param->cid);

    if ((p_vlan_info->user_vlanptr > MCHIP_CAP(SYS_CAP_MAX_VLAN_PTR)) && (p_vlan_info->user_vlanptr != 0xFFFF) && (p_vlan_info->user_vlanptr != 0xFFFE))
    {
        return CTC_E_INVALID_PARAM;
    }
    if (p_nh_param->aps_en)
    {
        return CTC_E_NOT_SUPPORT;
    }

    sal_memset(&nh_brg, 0, sizeof(sys_nh_param_brguc_t));

    SYS_NH_LOCK;
    nh_brg.hdr.nh_param_type = SYS_NH_TYPE_BRGUC;
    nh_brg.hdr.is_internal_nh = FALSE;
    nh_brg.nh_sub_type = SYS_NH_PARAM_BRGUC_SUB_TYPE_VLAN_EDIT;
    nh_brg.p_vlan_edit_info = p_vlan_info;
    nh_brg.loop_nhid = p_vlan_info->loop_nhid;
    nh_brg.p_vlan_edit_nh_param = p_nh_param;
    nh_brg.hdr.change_type = SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR;
    nh_brg.gport = p_nh_param->gport_or_aps_bridge_id;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_brg)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief This function is to create ipuc nexthop

 @param[in] nhid, nexthop ID

 @param[in] p_member_list, member list to be added to this nexthop

 @return CTC_E_XXX
 */
int32
sys_usw_ipuc_nh_create(uint8 lchip, uint32 nhid, ctc_ip_nh_param_t* p_nh_param)
{
    sys_nh_param_ipuc_t nh_param;
    ctc_ip_nh_param_t ipuc_param;
    uint32 arp_id = 0;
    int32 ret = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_param);

    if (CTC_FLAG_ISSET(p_nh_param->flag, CTC_IP_NH_FLAG_STRIP_MAC))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
        return CTC_E_NOT_SUPPORT;
    }

    if(!CTC_FLAG_ISSET(p_nh_param->flag, CTC_IP_NH_FLAG_UNROV))
    {
        /*unrov nexthop donot care oif parameter*/
        SYS_GLOBAL_PORT_CHECK(p_nh_param->oif.gport);
        CTC_MAX_VALUE_CHECK(p_nh_param->oif.vid, CTC_MAX_VLAN_ID);
        CTC_MAX_VALUE_CHECK(p_nh_param->oif.cvid, CTC_MAX_VLAN_ID);
        SYS_USW_CID_CHECK(lchip, p_nh_param->cid);
    }

    SYS_NH_LOCK;

    sal_memset(&nh_param, 0, sizeof(sys_nh_param_ipuc_t));
    sal_memset(&ipuc_param, 0, sizeof(ctc_ip_nh_param_t));
    nh_param.p_ipuc_param = &ipuc_param;

    arp_id = p_nh_param->arp_id;
    nh_param.hdr.l3if_id = p_nh_param->oif.ecmp_if_id;
    CTC_ERROR_GOTO(sys_usw_nh_get_arp_oif(lchip, arp_id, &p_nh_param->oif,
        (uint8*)p_nh_param->mac, &nh_param.hdr.is_drop, &nh_param.hdr.l3if_id), ret, error_proc);

    if(CTC_FLAG_ISSET(p_nh_param->flag, CTC_IP_NH_FLAG_UNROV) && arp_id)
    {
       SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Nexthop with arp id cannot support unrov \n");
       SYS_NH_UNLOCK;
       return CTC_E_INVALID_CONFIG;
    }

    CTC_ERROR_GOTO(sys_usw_nh_check_max_glb_nh_offset(lchip, p_nh_param->dsnh_offset), ret, error_proc);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d, dsnhoffset = %d, gport = %d, vid = %d, mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
                   nhid, p_nh_param->dsnh_offset, p_nh_param->oif.gport, p_nh_param->oif.vid, p_nh_param->mac[0], p_nh_param->mac[1],
                   p_nh_param->mac[2], p_nh_param->mac[3], p_nh_param->mac[4], p_nh_param->mac[5]);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "protection_gport = %d, protection_vid = %d, protection_mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
                   p_nh_param->p_oif.gport, p_nh_param->p_oif.vid, p_nh_param->p_mac[0], p_nh_param->p_mac[1],
                   p_nh_param->p_mac[2], p_nh_param->p_mac[3], p_nh_param->p_mac[4], p_nh_param->p_mac[5]);

    nh_param.hdr.nh_param_type = SYS_NH_TYPE_IPUC;
    nh_param.hdr.is_internal_nh = FALSE;
    nh_param.hdr.nhid = nhid;
    nh_param.p_ipuc_param = p_nh_param;
    nh_param.is_unrov_nh = CTC_FLAG_ISSET(p_nh_param->flag, CTC_IP_NH_FLAG_UNROV);  /* CTC_IP_NH_FLAG_UNROV*/

    CTC_ERROR_GOTO(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), ret, error_proc);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
error_proc:
    SYS_NH_UNLOCK;
    return ret;
}

/**
 @brief This function is to remove member from multicast bridge nexthop

 @param[in] nhid, nexthop id

 @return CTC_E_XXX
 */
int32
sys_usw_ipuc_nh_delete(uint8 lchip, uint32 nhid)
{
    sys_nh_info_dsnh_t dsnh;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, SYS_NH_CHANGE_TYPE_NH_DELETE, SYS_NH_TYPE_IPUC, &dsnh), p_usw_nh_api_master[lchip]->p_mutex);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_IPUC), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    if (dsnh.updateAd)
    {
        dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
    }

    return CTC_E_NONE;
}


/**
 @brief This function is to update ipuc nexthop

 @param[in] nhid, nexthop id
 @param[in] vid, vlan  id
 @param[in] gport, global destination port
 @param[in] mac, nexthop mac address
 @param[in] update_type, nexthop update type

 @return CTC_E_XXX
 */
int32
sys_usw_ipuc_nh_update(uint8 lchip, uint32 nhid, ctc_ip_nh_param_t* p_nh_param,
                             sys_nh_entry_change_type_t update_type)
{
    sys_nh_param_ipuc_t nh_param;
	 sys_nh_info_dsnh_t dsnh;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_param);

    sal_memset(&nh_param, 0, sizeof(sys_nh_param_ipuc_t));

    if (SYS_NH_CHANGE_TYPE_FWD_TO_UNROV != update_type)
    {
        SYS_GLOBAL_PORT_CHECK(p_nh_param->oif.gport);
        CTC_MAX_VALUE_CHECK(p_nh_param->oif.vid, CTC_MAX_VLAN_ID);
        CTC_MAX_VALUE_CHECK(p_nh_param->oif.cvid, CTC_MAX_VLAN_ID);
        SYS_USW_CID_CHECK(lchip, p_nh_param->cid);
    }

    SYS_NH_LOCK;
    nh_param.hdr.nhid = nhid;
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_IPUC;
    nh_param.hdr.change_type = update_type;
    nh_param.p_ipuc_param = p_nh_param;
    nh_param.hdr.l3if_id = p_nh_param->oif.ecmp_if_id;

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, update_type, SYS_NH_TYPE_IPUC, &dsnh), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;


    if (dsnh.updateAd)
    {
        dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
    }


    return CTC_E_NONE;
}

int32
sys_usw_nh_bind_dsfwd_cb(uint8 lchip, uint32 nhid, sys_nh_update_dsnh_param_t* p_update_dsnh)
{

    sys_nh_info_com_t* p_nh_info = NULL;
    sys_nh_info_bind_t** pp_bind_data = NULL;
    sys_nh_info_bind_t* bind_data = NULL;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, &p_nh_info), p_usw_nh_api_master[lchip]->p_mutex);

    if(!p_nh_info)
    {
        if(!p_update_dsnh->updateAd)
        {
            SYS_NH_UNLOCK;
            return CTC_E_NONE;
        }
        else
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop not exist \n");
            SYS_NH_UNLOCK;
            return CTC_E_NOT_EXIST;
        }
    }
    /*ecmp if MUST use merge Dsfwd mode, so can not bind nexthop*/
    if(p_nh_info->hdr.nh_entry_flags & SYS_NH_INFO_FLAG_USE_ECMP_IF)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " ecmp interface can not bind nexthop\n");
        SYS_NH_UNLOCK;
        return CTC_E_NONE;
    }

    switch(p_nh_info->hdr.nh_entry_type )
    {
        case SYS_NH_TYPE_IPUC:
        {
            sys_nh_info_ipuc_t* p_ipuc_info = (sys_nh_info_ipuc_t*)p_nh_info;

            if (p_update_dsnh->updateAd && p_ipuc_info->pd->bind_data)
            {
                SYS_NH_UNLOCK;
                return CTC_E_IN_USE;
            }

            pp_bind_data = &p_ipuc_info->pd->bind_data;

        }
            break;
        case SYS_NH_TYPE_IP_TUNNEL:
        {
            sys_nh_info_ip_tunnel_t* p_ip_tunnel_info = (sys_nh_info_ip_tunnel_t*)p_nh_info;

            /*use logic port list, no need to bind nexthop*/
            if(p_ip_tunnel_info->bind_ldp)
            {
                SYS_NH_UNLOCK;
                return CTC_E_NONE;
            }
            if (p_update_dsnh->updateAd && p_ip_tunnel_info->bind_data)
            {
                SYS_NH_UNLOCK;
                return CTC_E_IN_USE;
            }
            pp_bind_data = &p_ip_tunnel_info->bind_data;

        }
            break;
        case SYS_NH_TYPE_MPLS:
        {
            sys_nh_info_mpls_t* p_mpls_info = (sys_nh_info_mpls_t*)p_nh_info;

            if (p_update_dsnh->updateAd && p_mpls_info->pd->bind_data)
            {
                SYS_NH_UNLOCK;
                return CTC_E_IN_USE;
            }
            pp_bind_data = &p_mpls_info->pd->bind_data;
        }
            break;
        case SYS_NH_TYPE_TRILL:
        {
            sys_nh_info_trill_t* p_trill_info = (sys_nh_info_trill_t*)p_nh_info;

            if (p_update_dsnh->updateAd && p_trill_info->bind_data)
            {
                SYS_NH_UNLOCK;
                return CTC_E_IN_USE;
            }

            pp_bind_data = &p_trill_info->bind_data;

        }
            break;

        case SYS_NH_TYPE_MISC:
        {
            sys_nh_info_misc_t* p_misc_info = (sys_nh_info_misc_t*)p_nh_info;

            if (p_update_dsnh->updateAd && p_misc_info->bind_data)
            {
                SYS_NH_UNLOCK;
                return CTC_E_IN_USE;
            }

            pp_bind_data = &p_misc_info->bind_data;

        }
            break;
        case SYS_NH_TYPE_SRV6:
            {
                sys_nh_info_srv6_t* p_srv6_info = (sys_nh_info_srv6_t*)p_nh_info;
                if (p_update_dsnh->updateAd && p_srv6_info->bind_data)
                {
                    SYS_NH_UNLOCK;
                    return CTC_E_IN_USE;
                }
                pp_bind_data = &p_srv6_info->bind_data;
            }
            break;

        case SYS_NH_TYPE_APS:
        {
            sys_nh_info_aps_t* p_aps_info = (sys_nh_info_aps_t*)p_nh_info;

             if(DRV_FROM_AT(lchip))/*for at, working nhptr use dsipeapsbridge, no need binding*/
             {
                 SYS_NH_UNLOCK;
                 return CTC_E_NONE;
             }
            if (p_update_dsnh->updateAd && p_aps_info->bind_data)
            {
                SYS_NH_UNLOCK;
                return CTC_E_IN_USE;
            }

            pp_bind_data = &p_aps_info->bind_data;
        }
            break;
        default:
            SYS_NH_UNLOCK;
            return CTC_E_NONE;
            break;
    }

    /*first bind or update bind data*/
    if(NULL == (*pp_bind_data) || p_update_dsnh->updateAd)
    {
        if(NULL == (*pp_bind_data) && (NULL == (*pp_bind_data = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_info_bind_t)))))
        {
            SYS_NH_UNLOCK;
            return CTC_E_NO_MEMORY;
        }
        bind_data = *pp_bind_data;
        bind_data->bind_feature = p_update_dsnh->bind_feature;
        bind_data->bind_lchip = lchip;
        bind_data->updateAd = p_update_dsnh->updateAd;
        bind_data->data = p_update_dsnh->data;
        bind_data->chk_data = p_update_dsnh->chk_data;
    }
    else if(*pp_bind_data)
    {
        mem_free(*pp_bind_data);
        *pp_bind_data = NULL;
    }

    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief This function is to create mcast nexthop

 @param[in] groupid, basic met offset of this multicast nexthop

 @param[in] p_nh_mcast_group,  group and member information this multicast nexthop

 @return CTC_E_XXX
 */

int32
sys_usw_mcast_nh_create(uint8 lchip, uint32 groupid, sys_nh_param_mcast_group_t* p_nh_mcast_group)
{
    sys_nh_param_mcast_t nh_mcast;
	sys_nh_info_mcast_t* p_mcast_info = NULL;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "groupid = %d\n", groupid);

    /*Sanity Check*/
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_mcast_group);

    if (CTC_FLAG_ISSET(p_nh_mcast_group->flag, CTC_NH_MCAST_FLAG_LOGIC_REP) && (!(DRV_IS_TMM(lchip) || DRV_IS_TMG(lchip))))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " not support enable logic replication by group\n");
        return CTC_E_NOT_SUPPORT;
    }


    if (CTC_FLAG_ISSET(p_nh_mcast_group->flag, CTC_NH_MCAST_FLAG_2X_GRP_ID) &&
        (p_nh_mcast_group->is_mcast_profile||(groupid % 2)))
    {
        return CTC_E_INVALID_PARAM;
    }
    if ((!p_nh_mcast_group->is_mcast_profile)
        &&(!CTC_FLAG_ISSET(p_nh_mcast_group->flag, CTC_NH_MCAST_FLAG_LOGIC_REP)))
    {
        CTC_ERROR_RETURN(sys_usw_nh_check_max_glb_met_offset(lchip, CTC_FLAG_ISSET(p_nh_mcast_group->flag, CTC_NH_MCAST_FLAG_2X_GRP_ID)? (groupid + 1) : groupid));
    }

    LCHIP_CHECK(lchip);

    /*mcast profile donot suport stats&mirro*/
    if (((p_nh_mcast_group->is_mirror) || (p_nh_mcast_group->stats_valid)) && p_nh_mcast_group->is_mcast_profile)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " mcast profile donot support mirror or stats\n");
        return CTC_E_INVALID_PARAM;
    }

    if (p_nh_mcast_group->is_mirror && p_nh_mcast_group->stats_valid)
    {
        return CTC_E_INVALID_CONFIG;
    }

    sal_memset(&nh_mcast, 0, sizeof(sys_nh_param_mcast_t));
    if (SYS_CB_PTR(SYS_CB_STK_GET_MCAST_PROFILE_MET_OFFSET))
    {
        CTC_ERROR_RETURN(SYS_CB(SYS_CB_STK_GET_MCAST_PROFILE_MET_OFFSET, lchip, 0, &nh_mcast.profile_met_offset));
    }

    SYS_NH_LOCK;
    SYS_USW_REGISTER_WB_SYNC_EN(SYS_PP_BASE(lchip), CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_MCAST, 1);
    nh_mcast.is_mcast_profile = p_nh_mcast_group->is_mcast_profile;
    nh_mcast.hdr.nh_param_type = SYS_NH_TYPE_MCAST;
    if (p_nh_mcast_group->is_nhid_valid)
    {
        nh_mcast.hdr.nhid = p_nh_mcast_group->nhid;
        nh_mcast.hdr.is_internal_nh = FALSE;
    }
    else
    {   nh_mcast.hdr.nhid = SYS_NH_INVALID_NHID;
        nh_mcast.hdr.is_internal_nh = TRUE;
    }
    if (p_nh_mcast_group->is_mirror)
    {
        nh_mcast.hdr.have_dsfwd = TRUE;
    }

    nh_mcast.hdr.stats_valid = p_nh_mcast_group->stats_valid;
    nh_mcast.hdr.stats_id = p_nh_mcast_group->stats_id;

    nh_mcast.groupid = groupid;
    nh_mcast.p_member = &(p_nh_mcast_group->mem_info);
    nh_mcast.opcode = p_nh_mcast_group->opcode;
    nh_mcast.is_mirror = p_nh_mcast_group->is_mirror;
    nh_mcast.flag = p_nh_mcast_group->flag;

	CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_mcast)), p_usw_nh_api_master[lchip]->p_mutex);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_get_nhinfo_by_nhid(lchip, nh_mcast.hdr.nhid,
                                           (sys_nh_info_com_t**)&p_mcast_info), p_usw_nh_api_master[lchip]->p_mutex);
    p_nh_mcast_group->fwd_offset = p_mcast_info->hdr.dsfwd_offset;
    p_nh_mcast_group->nhid = nh_mcast.hdr.nhid;
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief This function is to update mcast nexthop

 @param[in] nhid,  nexthopid

 @return CTC_E_XXX
 */

int32
sys_usw_mcast_nh_delete(uint8 lchip, uint32 nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    SYS_USW_REGISTER_WB_SYNC_EN(SYS_PP_BASE(lchip), CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_MCAST, 1);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_MCAST), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

/**
 @brief This function is to update mcast nexthop

 @param[in] p_nh_mcast_group,  group and member information this multicast nexthop

 @return CTC_E_XXX
 */

int32
sys_usw_mcast_nh_update(uint8 lchip, sys_nh_param_mcast_group_t* p_nh_mcast_group)
{
    sys_nh_param_mcast_t nh_mcast;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_mcast_group);
    LCHIP_CHECK(lchip);

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %u\n", p_nh_mcast_group->nhid);
    sal_memset(&nh_mcast, 0, sizeof(sys_nh_param_mcast_t));
    if (SYS_CB_PTR(SYS_CB_STK_GET_RSV_TRUNK_NUM))
    {
        SYS_CB(SYS_CB_STK_GET_RSV_TRUNK_NUM, lchip, &(p_nh_mcast_group->mem_info.stk_rsv_mem));
    }    
    SYS_NH_LOCK;    
    nh_mcast.hdr.nh_param_type = SYS_NH_TYPE_MCAST;
    nh_mcast.p_member = &(p_nh_mcast_group->mem_info);
    nh_mcast.hdr.nhid = p_nh_mcast_group->nhid;
    nh_mcast.opcode = p_nh_mcast_group->opcode;
    nh_mcast.is_mcast_profile = p_nh_mcast_group->is_mcast_profile;
    SYS_USW_REGISTER_WB_SYNC_EN(SYS_PP_BASE(lchip), CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_MCAST, 1);
    SYS_USW_REGISTER_WB_SYNC_EN(SYS_PP_BASE(lchip), CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MASTER, 1);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, p_nh_mcast_group->nhid,
                                                 (sys_nh_param_com_t*)(&nh_mcast)), p_usw_nh_api_master[lchip]->p_mutex);

    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief This function is to traverse mcast nexthop

 @param[in] fn callback function to deal with all the ipuc entry

 @param[in] p_data data used by the callback function

 @return CTC_E_XXX
 */
int32
sys_usw_nh_traverse_mcast(uint8 lchip, ctc_nh_mcast_traverse_fn fn, ctc_nh_mcast_traverse_t* p_data)
{
    int32 ret = CTC_E_NONE;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(fn);
    CTC_PTR_VALID_CHECK(p_data);
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_traverse_mcast(lchip, fn, p_data), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return ret;
}

int32
sys_usw_mpls_nh_create_tunnel_label_api(uint8 lchip, uint16 tunnel_id,
                                           ctc_mpls_nexthop_tunnel_param_t* p_nh_param)
{
    int32 ret = CTC_E_NONE;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_nh_param);
    if (CTC_FLAG_ISSET(p_nh_param->nh_param.flag, CTC_MPLS_TUNNEL_NH_FLAG_LB_WITH_LOGIC_DST_PORT) && (0 == p_nh_param->nh_param.loop_nhid))
    {
        return CTC_E_INVALID_PARAM;
    }

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_mpls_nh_create_tunnel_label(lchip, tunnel_id, p_nh_param), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return ret;
}

int32
sys_usw_mpls_nh_remove_tunnel_label_api(uint8 lchip, uint16 tunnel_id)
{
    int32 ret = CTC_E_NONE;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_mpls_nh_remove_tunnel_label(lchip, tunnel_id), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return ret;
}

int32
sys_usw_mpls_nh_update_tunnel_label_api(uint8 lchip, uint16 tunnel_id, ctc_mpls_nexthop_tunnel_param_t* p_tunnel_param)
{
    int32 ret = CTC_E_NONE;
    ctc_slist_t* update_cb_list = NULL;
    ctc_slistnode_t* node = NULL;
    ctc_slistnode_t* next_node = NULL;
    sys_nh_update_dsnh_node_t* update_cb_node = NULL;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_tunnel_param);
    if (CTC_FLAG_ISSET(p_tunnel_param->nh_param.flag, CTC_MPLS_TUNNEL_NH_FLAG_LB_WITH_LOGIC_DST_PORT) && (0 == p_tunnel_param->nh_param.loop_nhid))
    {
        return CTC_E_INVALID_PARAM;
    }

    update_cb_list = ctc_slist_new();
    if (NULL == update_cb_list)
    {
        return CTC_E_NO_MEMORY;
    }
    SYS_NH_LOCK;
    ret = sys_usw_mpls_nh_update_tunnel_label(lchip, tunnel_id, p_tunnel_param, update_cb_list);
    SYS_NH_UNLOCK;
    CTC_SLIST_LOOP_DEL(update_cb_list, node, next_node)
    {
        update_cb_node = (sys_nh_update_dsnh_node_t*)node;
        if (CTC_E_NONE == ret)
        {
            update_cb_node->dsnh_info.updateAd(update_cb_node->dsnh_info.bind_lchip, update_cb_node->dsnh_info.data, &update_cb_node->dsnh_info);
        }
        mem_free(update_cb_node);
    }
    ctc_slist_free(update_cb_list);

    return ret;
}

int32
sys_usw_mpls_nh_get_tunnel_label_api(uint8 lchip, uint16 tunnel_id, ctc_mpls_nexthop_tunnel_param_t* p_tunnel_param)
{
    int32 ret = CTC_E_NONE;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_tunnel_param);
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_mpls_nh_get_tunnel_label(lchip, tunnel_id, p_tunnel_param), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return ret;
}

int32
sys_usw_mpls_nh_swap_tunnel_api(uint8 lchip, uint16 old_tunnel_id, uint16 new_tunnel_id)
{
    int32 ret = CTC_E_NONE;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_mpls_nh_swap_tunnel(lchip, old_tunnel_id, new_tunnel_id), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return ret;
}

/**
 @param[in] nhid  nexthop ID

 @param[in] dsnh_offset  DsNexthop offset used by this nexthop

 @param[in] p_nh_param  Nexthop param used to create this nexthop

 @return CTC_E_XXX
 */
int32
sys_usw_mpls_nh_create(uint8 lchip, uint32 nhid,   ctc_mpls_nexthop_param_t* p_nh_param)
{
    sys_nh_param_mpls_t nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_param);

    CTC_ERROR_RETURN(sys_usw_nh_check_max_glb_nh_offset(lchip, p_nh_param->dsnh_offset));

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d, dsnhoffset = %d\n", nhid, p_nh_param->dsnh_offset);
    SYS_NH_LOCK;

    sal_memset(&nh_param, 0, sizeof(sys_nh_param_mpls_t));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_MPLS;
    nh_param.hdr.is_internal_nh = FALSE;
    nh_param.hdr.nhid = nhid;
    nh_param.p_mpls_nh_param = p_nh_param;

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief This function is to remove mpls nexthop by nexthop id

 @param[in] nhid nexthop id

 @return CTC_E_XXX
 */
int32
sys_usw_mpls_nh_delete(uint8 lchip, uint32 nhid)
{
	sys_nh_info_dsnh_t dsnh;

	SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
	CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, SYS_NH_CHANGE_TYPE_NH_DELETE, SYS_NH_TYPE_MPLS,&dsnh),p_usw_nh_api_master[lchip]->p_mutex);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_MPLS), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

	if(dsnh.updateAd)
	{
		dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
	}

    return CTC_E_NONE;
}

/**
 @brief This function is to update mpls nexthop

 @param[in] nhid, nexthop id

 @param[in] p_nh_param nexthop paramter

 @return CTC_E_XXX
 */
int32
sys_usw_mpls_nh_update(uint8 lchip, uint32 nhid, ctc_mpls_nexthop_param_t* p_nh_param,
                             sys_nh_entry_change_type_t change_type)
{
    sys_nh_param_mpls_t nh_param;
	 sys_nh_info_dsnh_t dsnh;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(sys_nh_param_mpls_t));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_MPLS;
    nh_param.hdr.nhid = nhid;
    nh_param.p_mpls_nh_param = p_nh_param;
    nh_param.hdr.change_type = change_type;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);

	CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, change_type, SYS_NH_TYPE_MPLS,&dsnh),p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

	if(dsnh.updateAd)
	{
		dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
	}

    return CTC_E_NONE;
}

int32
sys_usw_ecmp_nh_create(uint8 lchip, uint32 nhid, ctc_nh_ecmp_nh_param_t* p_nh_parama)
{
    sys_nh_param_ecmp_t nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_nh_parama);
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(sys_nh_param_ecmp_t));

    nh_param.hdr.nh_param_type = SYS_NH_TYPE_ECMP;
    nh_param.hdr.is_internal_nh = FALSE;
    nh_param.p_ecmp_param = p_nh_parama;
    nh_param.hdr.nhid = nhid;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ECMP, 1);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ECMP_MEM, 1);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_ecmp_nh_delete(uint8 lchip, uint32 nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ECMP, 1);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ECMP_MEM, 1);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_ECMP), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_ecmp_nh_update(uint8 lchip, uint32 nhid, ctc_nh_ecmp_nh_param_t* p_nh_param)
{
    sys_nh_param_ecmp_t nh_param;


    CTC_PTR_VALID_CHECK(p_nh_param);

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(sys_nh_param_ecmp_t));

    nh_param.hdr.nh_param_type = SYS_NH_TYPE_ECMP;
    nh_param.hdr.nhid = nhid;

    nh_param.p_ecmp_param = p_nh_param;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ECMP, 1);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ECMP_MEM, 1);
     CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);

    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

/**
 @brief This function is to create IPE Loopback nexthop
 */
int32
sys_usw_iloop_nh_create(uint8 lchip, uint32 nhid, ctc_loopback_nexthop_param_t* p_nh_param)
{
    sys_nh_param_iloop_t nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_param);
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(sys_nh_param_iloop_t));

    nh_param.hdr.nh_param_type = SYS_NH_TYPE_ILOOP;
    nh_param.hdr.is_internal_nh = FALSE;
    nh_param.p_iloop_param = p_nh_param;
    nh_param.hdr.nhid = nhid;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_iloop_nh_delete(uint8 lchip, uint32 nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_ILOOP), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

/**
 @brief This function is to create rspan  nexthop
 */
int32
sys_usw_rspan_nh_create(uint8 lchip, uint32* nhid, uint32 dsnh_offset, ctc_rspan_nexthop_param_t* p_nh_param)
{
    sys_nh_param_rspan_t nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_param);
    CTC_PTR_VALID_CHECK(nhid);
    SYS_NH_LOCK;

    sal_memset(&nh_param, 0, sizeof(sys_nh_param_rspan_t));

    nh_param.hdr.nh_param_type = SYS_NH_TYPE_RSPAN;
    nh_param.hdr.is_internal_nh = (*nhid == CTC_MAX_UINT32_VALUE) ? TRUE : FALSE;
    nh_param.p_rspan_param = p_nh_param;
    nh_param.hdr.nhid = *nhid;
    nh_param.dsnh_offset = dsnh_offset;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);

    if (nh_param.hdr.is_internal_nh)
    {
        *nhid = nh_param.hdr.nhid;
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_rspan_nh_delete(uint8 lchip, uint32 nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_RSPAN), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_ip_tunnel_nh_create(uint8 lchip, uint32 nhid, ctc_ip_tunnel_nh_param_t* p_nh_param)
{
    sys_nh_param_ip_tunnel_t nh_param;
    uint32 arp_id = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_nh_param);

    sal_memset(&nh_param, 0, sizeof(nh_param));

    arp_id = p_nh_param->arp_id;
    CTC_ERROR_RETURN(sys_usw_nh_get_arp_oif(lchip, arp_id, &p_nh_param->oif, (uint8*)p_nh_param->mac, &nh_param.hdr.is_drop, &nh_param.hdr.l3if_id));
    if (!arp_id)
    {
        SYS_GLOBAL_PORT_CHECK(p_nh_param->oif.gport);
    }
    CTC_MAX_VALUE_CHECK(p_nh_param->tunnel_info.dscp_domain, 15);
    if (CTC_FLAG_ISSET(p_nh_param->flag, CTC_IP_NH_FLAG_LB_WITH_LOGIC_DST_PORT) && (0 == p_nh_param->loop_nhid))
    {
        return CTC_E_INVALID_PARAM;
    }

    CTC_ERROR_RETURN(sys_usw_nh_check_max_glb_nh_offset(lchip, p_nh_param->dsnh_offset));
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d, dsnhoffset = %d, gport = %d\n",
                   nhid, p_nh_param->dsnh_offset, p_nh_param->oif.gport);

    if(CTC_FLAG_ISSET(p_nh_param->flag, CTC_IP_NH_FLAG_UNROV) && arp_id)
    {
       SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Nexthop with arp id cannot support unrov \n");
       return CTC_E_INVALID_CONFIG;
    }

    SYS_NH_LOCK;
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_IP_TUNNEL;
    nh_param.hdr.is_internal_nh = FALSE;
    nh_param.hdr.nhid = nhid;
    nh_param.p_ip_nh_param = p_nh_param;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    if(g_usw_nh_master[lchip]->bind_ldp && DRV_IS_TSINGMA(lchip))
    {
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_offset_ref_cnt(lchip, nhid, 1), p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_ip_tunnel_nh_delete(uint8 lchip, uint32 nhid)
{
    sys_nh_info_dsnh_t dsnh;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, SYS_NH_CHANGE_TYPE_NH_DELETE, SYS_NH_TYPE_IP_TUNNEL, &dsnh), p_usw_nh_api_master[lchip]->p_mutex);
    if (g_usw_nh_master[lchip]->bind_ldp && DRV_IS_TSINGMA(lchip))
    {
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_offset_ref_cnt(lchip, nhid, 0), p_usw_nh_api_master[lchip]->p_mutex);
    }
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_IP_TUNNEL), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    if (dsnh.updateAd)
    {
        dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
    }
    return CTC_E_NONE;
}

int32
sys_usw_ip_tunnel_nh_update(uint8 lchip, uint32 nhid, ctc_ip_tunnel_nh_param_t* p_nh_param)
{
    sys_nh_param_ip_tunnel_t nh_param;
    sys_nh_info_dsnh_t dsnh;


    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    if (CTC_FLAG_ISSET(p_nh_param->flag, CTC_IP_NH_FLAG_LB_WITH_LOGIC_DST_PORT) && (0 == p_nh_param->loop_nhid))
    {
        return CTC_E_INVALID_PARAM;
    }
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(sys_nh_param_ip_tunnel_t));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_IP_TUNNEL;
    nh_param.hdr.nhid = nhid;
    nh_param.p_ip_nh_param = p_nh_param;

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_get_arp_oif(lchip, p_nh_param->arp_id, &p_nh_param->oif,
        (uint8*)p_nh_param->mac, &nh_param.hdr.is_drop, &nh_param.hdr.l3if_id), p_usw_nh_api_master[lchip]->p_mutex);

    if (p_nh_param->upd_type == CTC_NH_UPD_FWD_ATTR)
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR;
    }
    else if (p_nh_param->upd_type == CTC_NH_UPD_UNRSV_TO_FWD)
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UNROV_TO_FWD;
    }
    else
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_FWD_TO_UNROV;
    }

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
	CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, nh_param.hdr.change_type, SYS_NH_TYPE_IP_TUNNEL,&dsnh),p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;


	if(dsnh.updateAd)
	{
		dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
	}

    return CTC_E_NONE;
}

int32
sys_usw_wlan_tunnel_nh_create(uint8 lchip, uint32 nhid, ctc_nh_wlan_tunnel_param_t* p_nh_param)
{
    sys_nh_param_wlan_tunnel_t nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_nh_param);
    CTC_MAX_VALUE_CHECK(p_nh_param->dscp_domain, 15);
    CTC_MAX_VALUE_CHECK(p_nh_param->cos_domain, 7);
    CTC_MAX_VALUE_CHECK(p_nh_param->encrypt_id, 0x7f);
    CTC_MAX_VALUE_CHECK(p_nh_param->vlan_id, CTC_MAX_VLAN_ID);
    CTC_MAX_VALUE_CHECK(p_nh_param->flow_label_mode, CTC_NH_FLOW_LABEL_ASSIGN);
    CTC_MAX_VALUE_CHECK(p_nh_param->ecn_select, CTC_NH_ECN_SELECT_PACKET);
    CTC_MAX_VALUE_CHECK(p_nh_param->dscp_select, CTC_NH_DSCP_SELECT_NONE);

    CTC_ERROR_RETURN(sys_usw_nh_check_max_glb_nh_offset(lchip, p_nh_param->dsnh_offset));
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d, dsnhoffset = %d\n",
                   nhid, p_nh_param->dsnh_offset);
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(nh_param));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_WLAN_TUNNEL;
    nh_param.hdr.is_internal_nh = FALSE;
    nh_param.hdr.nhid = nhid;
    nh_param.p_wlan_nh_param = p_nh_param;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_wlan_tunnel_nh_delete(uint8 lchip, uint32 nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_WLAN_TUNNEL), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_wlan_tunnel_nh_update(uint8 lchip, uint32 nhid, ctc_nh_wlan_tunnel_param_t* p_nh_param)
{
    sys_nh_param_wlan_tunnel_t nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(sys_nh_param_wlan_tunnel_t));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_WLAN_TUNNEL;
    nh_param.hdr.nhid = nhid;
    nh_param.p_wlan_nh_param = p_nh_param;

    if (p_nh_param->upd_type == CTC_NH_UPD_FWD_ATTR)
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR;
    }
    else if (p_nh_param->upd_type == CTC_NH_UPD_UNRSV_TO_FWD)
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UNROV_TO_FWD;
    }
    else
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_FWD_TO_UNROV;
    }

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief The function is to add misc nexthop

*/

int32
sys_usw_nh_add_misc(uint8 lchip, uint32* nhid, ctc_misc_nh_param_t* p_nh_param, bool is_internal_nh)
{

    sys_nh_param_misc_t nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_nh_param);

     if (p_nh_param->is_oif)
    {
        SYS_GLOBAL_PORT_CHECK(p_nh_param->oif.gport);
        CTC_MAX_VALUE_CHECK(p_nh_param->oif.vid, CTC_MAX_VLAN_ID);
    }
    else
    {
        SYS_GLOBAL_PORT_CHECK(p_nh_param->gport);
    }

    CTC_ERROR_RETURN(sys_usw_nh_check_max_glb_nh_offset(lchip, p_nh_param->dsnh_offset));
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d, dsnhoffset = %d, gport = %d\n",
                   *nhid, p_nh_param->dsnh_offset, p_nh_param->gport);

    SYS_USW_CID_CHECK(lchip, p_nh_param->cid);
    if (CTC_FLAG_ISSET(p_nh_param->flag, CTC_MISC_NH_FLAG_LB_WITH_LOGIC_DST_PORT) && (0 == p_nh_param->loop_nhid))
    {
        return CTC_E_INVALID_PARAM;
    }

    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(nh_param));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_MISC;
    nh_param.hdr.is_internal_nh = is_internal_nh;

    if (FALSE == is_internal_nh)
    {
        nh_param.hdr.nhid = *nhid;
    }

    nh_param.p_misc_param = p_nh_param;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);

    if (TRUE == is_internal_nh)
    {
        *nhid = nh_param.hdr.nhid;
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief The function is to remove misc nexthop

*/
int32
sys_usw_nh_remove_misc(uint8 lchip, uint32 nhid)
{
	sys_nh_info_dsnh_t dsnh;

	SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
	CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, SYS_NH_CHANGE_TYPE_NH_DELETE, SYS_NH_TYPE_MISC,&dsnh),p_usw_nh_api_master[lchip]->p_mutex);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_MISC), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

	if(dsnh.updateAd)
	{
		dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
	}

    return CTC_E_NONE;
}


/**
 @brief This function is to update misc nexthop
 @return CTC_E_XXX
 */
int32
sys_usw_misc_nh_update(uint8 lchip, uint32 nhid, ctc_misc_nh_param_t* p_nh_param,
                             sys_nh_entry_change_type_t update_type)
{
    sys_nh_param_misc_t nh_param;
	sys_nh_info_dsnh_t dsnh;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_param);
    SYS_USW_CID_CHECK(lchip, p_nh_param->cid);

     if (p_nh_param->is_oif)
    {
        SYS_GLOBAL_PORT_CHECK(p_nh_param->oif.gport);
        CTC_MAX_VALUE_CHECK(p_nh_param->oif.vid, CTC_MAX_VLAN_ID);
    }
    else
    {
        SYS_GLOBAL_PORT_CHECK(p_nh_param->gport);
    }

    sal_memset(&nh_param, 0, sizeof(sys_nh_param_misc_t));

    SYS_NH_LOCK;
    nh_param.hdr.nhid = nhid;
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_MISC;
    nh_param.hdr.change_type = update_type;
    nh_param.p_misc_param = p_nh_param;

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
	CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, update_type,SYS_NH_TYPE_MISC,&dsnh),p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

	if(dsnh.updateAd)
	{
		dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
	}

    return CTC_E_NONE;
}


int32
sys_usw_nh_trill_create(uint8 lchip, uint32 nhid, ctc_nh_trill_param_t* p_nh_param)
{
    sys_nh_param_trill_t nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_nh_param);
    SYS_GLOBAL_PORT_CHECK(p_nh_param->oif.gport);

    CTC_ERROR_RETURN(sys_usw_nh_check_max_glb_nh_offset(lchip, p_nh_param->dsnh_offset));
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d, dsnhoffset = %d, gport = %d\n",
                   nhid, p_nh_param->dsnh_offset, p_nh_param->oif.gport);
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(nh_param));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_TRILL;
    nh_param.hdr.is_internal_nh = FALSE;
    nh_param.hdr.nhid = nhid;
    nh_param.p_trill_nh_param = p_nh_param;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_trill_delete(uint8 lchip, uint32 nhid)
{
	sys_nh_info_dsnh_t dsnh;

	SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
	CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, SYS_NH_CHANGE_TYPE_NH_DELETE, SYS_NH_TYPE_TRILL,&dsnh),p_usw_nh_api_master[lchip]->p_mutex);
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_TRILL), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;


	if(dsnh.updateAd)
	{
		dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
	}

    return CTC_E_NONE;
}

int32
sys_usw_nh_trill_update(uint8 lchip, uint32 nhid, ctc_nh_trill_param_t* p_nh_param)
{
    sys_nh_param_trill_t nh_param;
	 sys_nh_info_dsnh_t dsnh;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(sys_nh_param_trill_t));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_TRILL;
    nh_param.hdr.nhid = nhid;
    nh_param.p_trill_nh_param = p_nh_param;

    if (p_nh_param->upd_type == CTC_NH_UPD_FWD_ATTR)
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR;
    }
    else if (p_nh_param->upd_type == CTC_NH_UPD_UNRSV_TO_FWD)
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UNROV_TO_FWD;
    }
    else
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_FWD_TO_UNROV;
    }

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
	CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, nhid, nh_param.hdr.change_type, SYS_NH_TYPE_TRILL,&dsnh),p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

	if(dsnh.updateAd)
	{
		dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
	}

    return CTC_E_NONE;
}

int32
sys_usw_nh_add_udf_profile(uint8 lchip, ctc_nh_udf_profile_param_t* p_edit)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_edit);
    SYS_NH_LOCK;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MASTER, 1);
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_add_udf_profile(lchip, p_edit), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_remove_udf_profile(uint8 lchip, uint8 profile_id)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MASTER, 1);
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_remove_udf_profile(lchip, profile_id), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}


int32
sys_usw_nh_add_fp(uint8 lchip, ctc_nh_fp_edit_t* p_edit, uint8 is_internal)
{
   if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_edit);
    SYS_NH_LOCK;
    if (MCHIP_NH(lchip)->add_fp)
    {
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_FP, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(MCHIP_NH(lchip)->add_fp(lchip, p_edit, is_internal), p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_remove_fp(uint8 lchip, uint32 fp_id)
{
    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    if (MCHIP_NH(lchip)->remove_fp)
    {
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_FP, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(MCHIP_NH(lchip)->remove_fp(lchip, fp_id), p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_update_fp(uint8 lchip, ctc_nh_fp_edit_t* p_edit)
{
   if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_edit);
    SYS_NH_LOCK;
    if (MCHIP_NH(lchip)->update_fp)
    {
        CTC_ERROR_RETURN_WITH_UNLOCK(MCHIP_NH(lchip)->update_fp(lchip, p_edit), p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}


int32
sys_usw_nh_get_fp_info(uint8 lchip, uint32 fp_id, sys_nh_info_dsnh_t* p_fp_info)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    if (MCHIP_NH(lchip)->get_fp_info)
    {
        CTC_ERROR_RETURN_WITH_UNLOCK(MCHIP_NH(lchip)->get_fp_info(lchip, fp_id, p_fp_info), p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_aps_nh_create(uint8 lchip, uint32 id, ctc_nh_aps_param_t* p_nh_param)
{
    sys_nh_param_aps_t nh_param;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_nh_param);
    CTC_MAX_VALUE_CHECK(p_nh_param->type, CTC_NH_APS_TYPE_MAX - 1);
    SYS_NH_LOCK;
    if (p_nh_param->type == CTC_NH_APS_TYPE_TUNNEL)
    {
        if (id > 0xFFFF)
        {
            SYS_NH_UNLOCK;
            return CTC_E_INVALID_PARAM;
        }
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MPLS_TUNNEL, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_create_tunnel_aps(lchip, id, p_nh_param), p_usw_nh_api_master[lchip]->p_mutex);
    }
    else if(p_nh_param->type == CTC_NH_APS_TYPE_SRH)
    {
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_SRH, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_create_srh_aps(lchip, id, p_nh_param), p_usw_nh_api_master[lchip]->p_mutex);
    }
    else
    {
        sal_memset(&nh_param, 0, sizeof(sys_nh_param_aps_t));
        nh_param.hdr.nh_param_type = SYS_NH_TYPE_APS;
        nh_param.hdr.is_internal_nh = FALSE;
        nh_param.p_aps_param = p_nh_param;
        nh_param.hdr.nhid = id;
        if (!DRV_FROM_AT(lchip))
        {
            nh_param.hdr.have_dsfwd = 1;                /*must use dsfwd mode otherwise have lock problem in muti ctc_shell enviroment*/
        }
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_APS, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_aps_nh_delete(uint8 lchip, uint32 id, uint8 type)
{
    sys_nh_info_dsnh_t dsnh;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", id);

    SYS_NH_INIT_CHECK;
    CTC_MAX_VALUE_CHECK(type, CTC_NH_APS_TYPE_MAX - 1);

    sal_memset(&dsnh, 0, sizeof(dsnh));
    if (type == CTC_NH_APS_TYPE_NH)
    {
        SYS_NH_LOCK;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_APS, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, id, SYS_NH_CHANGE_TYPE_NH_DELETE, SYS_NH_TYPE_APS, &dsnh), p_usw_nh_api_master[lchip]->p_mutex);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, id, SYS_NH_TYPE_APS), p_usw_nh_api_master[lchip]->p_mutex);
    }
    else if(type == CTC_NH_APS_TYPE_TUNNEL)
    {
        SYS_NH_LOCK;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MPLS_TUNNEL, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_delete_tunnel_aps(lchip, id), p_usw_nh_api_master[lchip]->p_mutex);
    }
    else
    {
        SYS_NH_LOCK;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_SRH, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_delete_srh_aps(lchip, id), p_usw_nh_api_master[lchip]->p_mutex);
    }

    SYS_NH_UNLOCK;

    if (dsnh.updateAd)
    {
        dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
    }
    return CTC_E_NONE;
}


int32
sys_usw_aps_nh_update(uint8 lchip, uint32 id, ctc_nh_aps_param_t* p_nh_param)
{
    sys_nh_param_aps_t nh_param;
	 sys_nh_info_dsnh_t dsnh;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", id);
    CTC_PTR_VALID_CHECK(p_nh_param);

    SYS_NH_INIT_CHECK;
    CTC_MAX_VALUE_CHECK(p_nh_param->type, CTC_NH_APS_TYPE_MAX - 1);
    CTC_MAX_VALUE_CHECK(id, 0xFFFF);

    sal_memset(&nh_param, 0, sizeof(sys_nh_param_aps_t));

    SYS_NH_LOCK;
    if (p_nh_param->type == CTC_NH_APS_TYPE_TUNNEL)
    {
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MPLS_TUNNEL, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_tunnel_aps(lchip, id, p_nh_param), p_usw_nh_api_master[lchip]->p_mutex);
		dsnh.updateAd = NULL;
    }
    else if (p_nh_param->type == CTC_NH_APS_TYPE_SRH)
    {
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_SRH, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_srh_aps(lchip, id, p_nh_param), p_usw_nh_api_master[lchip]->p_mutex);
    }
    else
    {
        nh_param.hdr.nhid = id;
        nh_param.hdr.nh_param_type = SYS_NH_TYPE_APS;
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR;
        nh_param.p_aps_param = p_nh_param;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_APS, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, id, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
		CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, id, SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR, SYS_NH_TYPE_APS,&dsnh), p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    if(dsnh.updateAd)
	{
		dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
	}


    return CTC_E_NONE;
}

int32
sys_usw_nh_set_pw_working_path(uint8 lchip, uint32 nhid, uint8 is_working)
{
    int32 ret = 0;
    sys_nh_info_com_t* p_nh_com_info;
    sys_nh_info_aps_t* p_nh_aps_info;

    SYS_NH_LOCK;
    CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, (sys_nh_info_com_t**)&p_nh_com_info), ret, error_proc);
    p_nh_aps_info = (sys_nh_info_aps_t*)p_nh_com_info;
    if (SYS_NH_TYPE_APS != p_nh_com_info->hdr.nh_entry_type)
    {
         SYS_NH_UNLOCK;
        return CTC_E_NONE;
    }
    ret = _sys_usw_nh_set_pw_working_path(lchip, is_working, p_nh_aps_info);
error_proc:
    SYS_NH_UNLOCK;
    return ret;
}

int32
sys_usw_nh_update_oam_en(uint8 lchip, uint32 nhid, sys_nh_update_oam_info_t *p_oam_info)
{
    sys_nh_info_com_t* p_nh_com_info;
    sys_nh_info_mpls_t* p_nh_mpls_info = NULL;
    ds0_t  ds_edit_mpls;
    uint32 cmd = 0;
    uint32 offset = 0;
    sys_nh_db_mpls_tunnel_t* p_mpls_tunnel = NULL;
    int32 ret = 0;
    uint8 is_sr = 0;
    uint8 is_12w = 1;
    uint32 tbl_id = 0;
    uint8 is_pw = 0;
    /*uint8 aps_en = 0;*/

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_LOCK;
    CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, (sys_nh_info_com_t**)&p_nh_com_info), ret, error_proc);

    /*SYS_NH_TYPE_APS: mep should be configrured on the member nexthop, so the aps netxhop don't support  update_oam_en */
    if (SYS_NH_TYPE_MPLS == p_nh_com_info->hdr.nh_entry_type)
    {
        p_nh_mpls_info = (sys_nh_info_mpls_t*)p_nh_com_info;
        if (!p_nh_mpls_info)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Entry not exist \n");
            ret = CTC_E_NOT_EXIST;
            goto error_proc;
        }
        CTC_ERROR_GOTO(sys_usw_nh_lkup_mpls_tunnel(lchip, p_nh_mpls_info->tunnel_id, &p_mpls_tunnel), ret, error_proc);

        /*aps_en = CTC_FLAG_ISSET(p_nh_mpls_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN);*/
        if (CTC_FLAG_ISSET(p_nh_mpls_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L3EDIT))
        {
             /*PW nexthop*/
             SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Update pw lm ,  innerEditPtr = %d\n",
                            p_nh_mpls_info->dsl3edit_offset);

            offset = p_nh_mpls_info->dsl3edit_offset;
            is_pw = 1;
        }
        else
        {   /*tunnel with aps,only need consider LSP, Because SPME Nexthop will be regarded as LSP Nexthp.*/
            /*oam lock on tunnel, here nhid means tunnel id*/

            if (!p_mpls_tunnel)
            {
                ret = CTC_E_NOT_EXIST;
                goto error_proc;
            }

            offset = p_mpls_tunnel->lsp_offset;

            is_sr = CTC_FLAG_ISSET(p_mpls_tunnel->flag, SYS_NH_MPLS_TUNNEL_FLAG_IS_SR) && !DRV_IS_DUET2(lchip);
            if (DRV_FROM_TMM(lchip))
            {
                is_12w = CTC_FLAG_ISSET(p_mpls_tunnel->flag, SYS_NH_MPLS_TUNNEL_FLAG_IS_SR)?1:0;
            }
        }

        if (offset == 0)
        {  /*invalid nexthop */
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Invalid pointer \n");
            ret = CTC_E_INVALID_PTR;
            goto error_proc;
        }

        if (is_sr)
        {
            tbl_id = DRV_FROM_TMM(lchip)? (is_12w? DsL3EditAddMpls4X_t : DsL3EditAddMpls2X_t) : DsL3EditMpls12W_t;
            cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
            CTC_ERROR_GOTO(DRV_IOCTL(lchip, offset, cmd, &ds_edit_mpls), ret, error_proc);
            if (DRV_FROM_TMM(lchip))
            {
                if (p_oam_info->lock_en)
                {
                    SetDsL3EditAddMpls4X(V, discardType_f, &ds_edit_mpls, 1);
                    SetDsL3EditAddMpls4X(V, discard_f,    &ds_edit_mpls, 1);
                }
                else
                {
                    SetDsL3EditAddMpls4X(V, discardType_f, &ds_edit_mpls, 0);
                    SetDsL3EditAddMpls4X(V, discard_f,    &ds_edit_mpls, 0);
                }
            }
            else
            {
                if (p_oam_info->lock_en)
                {
                    SetDsL3EditMpls12W(V, discardType_f, &ds_edit_mpls, 1);
                    SetDsL3EditMpls12W(V, discard_f,    &ds_edit_mpls, 1);
                }
                else
                {
                    SetDsL3EditMpls12W(V, discardType_f, &ds_edit_mpls, 0);
                    SetDsL3EditMpls12W(V, discard_f,    &ds_edit_mpls, 0);
                }
            }
            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            CTC_ERROR_GOTO(DRV_IOCTL(lchip, offset, cmd, &ds_edit_mpls), ret, error_proc);
        }
        else
        {
            DsL3Edit6W3rd_m dsmpls6w;
            if (p_mpls_tunnel && CTC_FLAG_ISSET(p_mpls_tunnel->flag, SYS_NH_MPLS_TUNNEL_FLAG_IS_SPME))
            {
                tbl_id = DsL3Edit6W3rd_t;
                cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
                CTC_ERROR_GOTO(DRV_IOCTL(lchip, (offset/2), cmd, &dsmpls6w), ret, error_proc);
                if (offset & 0x1)
                {
                    sal_memcpy(&ds_edit_mpls, ((uint8*)&dsmpls6w+DRV_TABLE_ENTRY_SIZE(lchip, DsL3Edit3W3rd_t)), DRV_TABLE_ENTRY_SIZE(lchip, DsL3Edit3W3rd_t));
                }
                else
                {
                    sal_memcpy(&ds_edit_mpls, ((uint8*)&dsmpls6w), DRV_TABLE_ENTRY_SIZE(lchip, DsL3Edit3W3rd_t));
                }
            }
            else
            {
                if (DRV_FROM_AT(lchip) && is_pw)
                {
                    tbl_id = DsL3EditAddMpls1X0_t;
                }
                else
                {
                    tbl_id = DRV_FROM_TMM(lchip)? DsL3EditAddMpls1X_t : DsL3EditMpls3W_t;
                }
                cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
                CTC_ERROR_GOTO(DRV_IOCTL(lchip, offset, cmd, &ds_edit_mpls), ret, error_proc);
            }
            if (DRV_FROM_TMM(lchip))
            {
                if (p_oam_info->lm_en)
                {
                    SetDsL3EditAddMpls1X(V, mplsOamIndex_f, &ds_edit_mpls, p_oam_info->oam_mep_index);
                }
                else
                {
                    SetDsL3EditAddMpls1X(V, mplsOamIndex_f, &ds_edit_mpls, 0);
                }

                if (p_oam_info->lock_en)
                {
                    SetDsL3EditAddMpls1X(V, discardType_f, &ds_edit_mpls, 1);
                    SetDsL3EditAddMpls1X(V, discard_f,    &ds_edit_mpls, 1);
                }
                else
                {
                    SetDsL3EditAddMpls1X(V, discardType_f, &ds_edit_mpls, 0);
                    SetDsL3EditAddMpls1X(V, discard_f,    &ds_edit_mpls, 0);
                }
            }
            else
            {
                if (p_oam_info->lm_en)
                {
                    SetDsL3EditMpls3W(V, mplsOamIndex_f, &ds_edit_mpls, p_oam_info->oam_mep_index);
                }
                else
                {
                    SetDsL3EditMpls3W(V, mplsOamIndex_f, &ds_edit_mpls, 0);
                }

                if (p_oam_info->lock_en)
                {
                    SetDsL3EditMpls3W(V, discardType_f, &ds_edit_mpls, 1);
                    SetDsL3EditMpls3W(V, discard_f,    &ds_edit_mpls, 1);
                }
                else
                {
                    SetDsL3EditMpls3W(V, discardType_f, &ds_edit_mpls, 0);
                    SetDsL3EditMpls3W(V, discard_f,    &ds_edit_mpls, 0);
                }
            }
            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            if(p_mpls_tunnel && CTC_FLAG_ISSET(p_mpls_tunnel->flag, SYS_NH_MPLS_TUNNEL_FLAG_IS_SPME))
            {
                if (offset & 0x1)
                {
                    sal_memcpy((uint8*)&dsmpls6w+ DRV_TABLE_ENTRY_SIZE(lchip, DsL3Edit3W3rd_t), &ds_edit_mpls, DRV_TABLE_ENTRY_SIZE(lchip, DsL3Edit3W3rd_t));
                }
                else
                {
                    sal_memcpy((uint8*)&dsmpls6w, &ds_edit_mpls, DRV_TABLE_ENTRY_SIZE(lchip, DsL3Edit3W3rd_t));
                }
                sal_memcpy(&ds_edit_mpls, (uint8*)&dsmpls6w, DRV_TABLE_ENTRY_SIZE(lchip, DsL3Edit6W3rd_t));
                CTC_ERROR_GOTO(DRV_IOCTL(lchip, offset/2, cmd, &ds_edit_mpls), ret, error_proc);
            }
            else
            {
                CTC_ERROR_GOTO(DRV_IOCTL(lchip, offset, cmd, &ds_edit_mpls), ret, error_proc);
            }
        }
    }
    else if (SYS_NH_TYPE_IPUC == p_nh_com_info->hdr.nh_entry_type)
    {
        sys_nh_info_ipuc_t* p_nh_ipuc_info = NULL;
        p_nh_ipuc_info = (sys_nh_info_ipuc_t*)p_nh_com_info;
        if (!p_nh_ipuc_info)
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Entry not exist \n");
            ret = CTC_E_NOT_EXIST;
            goto error_proc;
        }
        /*aps_en = CTC_FLAG_ISSET(p_nh_ipuc_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_APS_EN);*/
    }
    else
    {
        ret = CTC_E_INVALID_CONFIG;
        goto error_proc;
    }

    if (p_oam_info->update_type == 1)
    {
        sys_nh_oam_info_t oam_info;
        sal_memset(&oam_info, 0, sizeof(sys_nh_oam_info_t));

        /*aps destmap used dsapsbridge */
        oam_info.mep_index = p_oam_info->mep_index;
        oam_info.mep_type = p_oam_info->mep_type;
        CTC_ERROR_GOTO(_sys_usw_nh_update_oam_ref_info(lchip, p_nh_com_info, &oam_info, p_oam_info->dsma_en), ret, error_proc);
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_INFO_COM, 1);
    }

error_proc:
    SYS_NH_UNLOCK;
    return ret;
}

int32
sys_usw_nh_add_srh_edit(uint8 lchip, uint32* srh_id, ctc_nh_srh_edit_param_t* p_nh_param)
{
   if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(srh_id);
    CTC_PTR_VALID_CHECK(p_nh_param);
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_add_srh_id(lchip, srh_id, p_nh_param), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_remove_srh_edit(uint8 lchip, uint32 srh_id)
{
   if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_remove_srh_id(lchip, srh_id), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_update_srh_edit(uint8 lchip, uint32 srh_id, ctc_nh_srh_edit_param_t* p_nh_param)
{
    int32 ret = CTC_E_NONE;
    sys_com_ldp_update_t  update_param = {0};

    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_param);

    SYS_NH_LOCK;
    ret = sys_usw_nh_update_srh_id(lchip, srh_id, p_nh_param, &update_param);
    SYS_NH_UNLOCK;

    /*update ldp underlay change !!!!!!!!!!!!!!*/
    if ((CTC_E_NONE == ret) && update_param.is_update)
    {
        update_param.ldp = SYS_COM_LDP_SRH_ID(srh_id);
        /*Update DsMac*/
        SYS_CB(SYS_CB_LDP_UPDATE_L2, lchip, &update_param);

        /*Update DsIP*/
        SYS_CB(SYS_CB_LDP_UPDATE_L3, lchip, &update_param);

        /*Update DsAcl*/
        SYS_CB(SYS_CB_LDP_UPDATE_ACL, lchip, &update_param);
    }

    return ret;
}

int32
sys_usw_nh_srv6_create(uint8 lchip, uint32 nhid, ctc_nh_srv6_param_t* p_nh_param)
{
    sys_nh_param_srv6_t nh_param;

   if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_nh_param);
    SYS_USW_CID_CHECK(lchip, p_nh_param->cid);

    sal_memset(&nh_param, 0, sizeof(nh_param));

    CTC_MAX_VALUE_CHECK(p_nh_param->dscp_domain, 15);
    if (CTC_FLAG_ISSET(p_nh_param->flag, CTC_NH_SRV6_FLAG_LB_WITH_LOGIC_DST_PORT) && (0 == p_nh_param->loop_nhid))
    {
        return CTC_E_INVALID_PARAM;
    }
    CTC_ERROR_RETURN(sys_usw_nh_check_max_glb_nh_offset(lchip, p_nh_param->dsnh_offset));
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d, dsnhoffset = %d, gport = %d\n",
                   nhid, p_nh_param->dsnh_offset, nh_param.oif.gport);

    SYS_NH_LOCK;
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_SRV6;
    nh_param.hdr.is_internal_nh = FALSE;
    nh_param.hdr.nhid = nhid;
    nh_param.p_srv6_nh_param = p_nh_param;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_srv6_delete(uint8 lchip, uint32 nhid)
{
    uint8 gchip_id = 0;
    sys_com_ldp_update_t  update_param = {0};

    if (!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_SRV6), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    sys_usw_get_gchip_id(lchip, &gchip_id);
    update_param.is_update = TRUE;
    update_param.nhid = nhid;
    update_param.is_del = TRUE;
    update_param.is_srv6 = TRUE;
    update_param.destmap = SYS_ENCODE_DESTMAP(gchip_id, SYS_RSV_PORT_DROP_ID);
    update_param.dsnh_valid = 1;
    update_param.dsnh_offset = SYS_USW_DROP_NH_OFFSET;

    /*Update DsMac*/
    SYS_CB(SYS_CB_NHID_UPDATE_L2, lchip, &update_param);

    /*Update DsIP*/
    SYS_CB(SYS_CB_NHID_UPDATE_L3, lchip, &update_param);

    /*Update DsAcl*/
    SYS_CB(SYS_CB_NHID_UPDATE_ACL, lchip, &update_param);

    return CTC_E_NONE;
}


int32
sys_usw_nh_srv6_update(uint8 lchip, uint32 nhid, ctc_nh_srv6_param_t* p_nh_param)
{
    sys_nh_param_srv6_t nh_param;
    sys_com_ldp_update_t  update_param = {0};

    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_INIT_CHECK;
    if (CTC_FLAG_ISSET(p_nh_param->flag, CTC_NH_SRV6_FLAG_LB_WITH_LOGIC_DST_PORT) && (0 == p_nh_param->loop_nhid))
    {
        return CTC_E_INVALID_PARAM;
    }
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(sys_nh_param_srv6_t));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_SRV6;
    nh_param.hdr.nhid = nhid;
    nh_param.p_srv6_nh_param = p_nh_param;
    nh_param.p_ldp_update = &update_param;

    if (p_nh_param->upd_type == CTC_NH_UPD_FWD_ATTR)
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR;
    }
    else if (p_nh_param->upd_type == CTC_NH_UPD_UNRSV_TO_FWD)
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UNROV_TO_FWD;
    }
    else
    {
        nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_FWD_TO_UNROV;
    }

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    sys_usw_nh_set_dirty_flag(lchip, nhid, 1);
    SYS_NH_UNLOCK;

    /*update ldp underlay change !!!!!!!!!!!!!!*/
    if (update_param.is_update)
    {
        /*Update DsMac*/
        SYS_CB(SYS_CB_NHID_UPDATE_L2, lchip, &update_param);

        /*Update DsIP*/
        SYS_CB(SYS_CB_NHID_UPDATE_L3, lchip, &update_param);

        /*Update DsAcl*/
        SYS_CB(SYS_CB_NHID_UPDATE_ACL, lchip, &update_param);
    }
    SYS_NH_LOCK;
    sys_usw_nh_set_dirty_flag(lchip, nhid, 0);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_add_overlay_tunnel(uint8 lchip, uint32 ldp, ctc_nh_ol_tunnel_t* p_ol_tunnel)
{
    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_ol_tunnel);

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_add_ol_tunnel(lchip, ldp, p_ol_tunnel), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}
int32
sys_usw_nh_remove_overlay_tunnel(uint8 lchip, uint32 ldp)
{

    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_remove_ol_tunnel(lchip, ldp), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}
int32
sys_usw_nh_get_overlay_tunnel(uint8 lchip, uint32 ldp, ctc_nh_ol_tunnel_t* p_ol_tunnel)
{
    int32 ret = CTC_E_NONE;

    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_ol_tunnel);

    SYS_NH_LOCK;
    ret = _sys_usw_nh_get_ol_tunnel(lchip, ldp, p_ol_tunnel);
    SYS_NH_UNLOCK;
    return ret;
}
int32
sys_usw_nh_update_overlay_tunnel(uint8 lchip, uint32 ldp, ctc_nh_ol_tunnel_t* p_ol_tunnel)
{
    sys_com_ldp_update_t  update_param = {0};

    if(!DRV_FROM_TM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_ol_tunnel);


    SYS_NH_LOCK;
    if(DRV_IS_TSINGMA(lchip))
    {
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ip_tunnel(lchip, ldp, p_ol_tunnel, &update_param), p_usw_nh_api_master[lchip]->p_mutex);
    }
    else
    {
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ol_tunnel(lchip, ldp, p_ol_tunnel, &update_param), p_usw_nh_api_master[lchip]->p_mutex);
    }
    sys_usw_nh_ol_tunnel_set_dirty_flag(lchip, ldp, 1);
    SYS_NH_UNLOCK;

    /*update ldp underlay change !!!!!!!!!!!!!!*/
    if (update_param.is_update)
    {
        update_param.ldp = ldp;
        /*Update DsMac*/
        SYS_CB(SYS_CB_LDP_UPDATE_L2, lchip, &update_param);

        /*Update DsIP*/
        SYS_CB(SYS_CB_LDP_UPDATE_L3, lchip, &update_param);

        /*Update DsAcl*/
        SYS_CB(SYS_CB_LDP_UPDATE_ACL, lchip, &update_param);
    }

    SYS_NH_LOCK;
    sys_usw_nh_ol_tunnel_set_dirty_flag(lchip, ldp, 0);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_add_overlay_vni(uint8 lchip, uint32* ol_vni, ctc_nh_ol_vni_t* p_ol_vni)
{
    sys_nh_param_ol_vni_t nh_param;
    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_ol_vni);
    SYS_USW_CID_CHECK(lchip, p_ol_vni->cid);
    if(CTC_WB_ENABLE(lchip) && g_usw_nh_master[lchip]->overlay_ovi_num >= SYS_WB_NH_SUBID_VNI_NUM)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(&nh_param, 0, sizeof(nh_param));

    CTC_ERROR_RETURN(sys_usw_nh_check_max_glb_nh_offset(lchip, p_ol_vni->dsnh_offset));
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "dsnhoffset = %d\n", p_ol_vni->dsnh_offset);

    SYS_NH_LOCK;
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_OVERLAY_VNI;
    nh_param.hdr.is_internal_nh = TRUE;
    nh_param.p_ol_vni_param = p_ol_vni;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    *ol_vni = nh_param.hdr.nhid;
    g_usw_nh_master[lchip]->overlay_ovi_num++;
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "ol_vni = %u\n",*ol_vni);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}
int32
sys_usw_nh_remove_overlay_vni(uint8 lchip, uint32 ol_vni)
{
    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "ol_vni = %d\n", ol_vni);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, ol_vni, SYS_NH_TYPE_OVERLAY_VNI), p_usw_nh_api_master[lchip]->p_mutex);
    g_usw_nh_master[lchip]->overlay_ovi_num--;
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}
int32
sys_usw_nh_update_overlay_vni(uint8 lchip, uint32 ol_vni, ctc_nh_ol_vni_t* p_ol_vni)
{
    sys_nh_param_ol_vni_t nh_param;

   if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "ol_vni = %d\n", ol_vni);
    SYS_USW_CID_CHECK(lchip, p_ol_vni->cid);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    sal_memset(&nh_param, 0, sizeof(nh_param));
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_OVERLAY_VNI;
    nh_param.hdr.nhid = ol_vni;
    nh_param.p_ol_vni_param = p_ol_vni;

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, ol_vni, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}


int32
sys_usw_nh_add_overlay(uint8 lchip, uint32 nhid, ctc_nh_overlay_param_t* p_nh_param)
{
    sys_nh_param_overlay_t nh_param;

   if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_nh_param);

    sal_memset(&nh_param, 0, sizeof(nh_param));

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    SYS_NH_LOCK;
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_OVERLAY;
    nh_param.hdr.is_internal_nh = FALSE;
    nh_param.hdr.nhid = nhid;
    nh_param.p_overlay_nh_param = p_nh_param;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_create(lchip, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_update_overlay(uint8 lchip, uint32 nhid, ctc_nh_overlay_param_t* p_nh_param)
{
    sys_com_ldp_update_t  update_param = {0};
    sys_nh_param_overlay_t nh_param;

    if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_param);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

    sal_memset(&nh_param, 0, sizeof(nh_param));
    SYS_NH_LOCK;
    nh_param.hdr.nhid = nhid;
    nh_param.hdr.nh_param_type = SYS_NH_TYPE_OVERLAY;
    nh_param.hdr.change_type = SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR;
    nh_param.p_overlay_nh_param = p_nh_param;
    nh_param.p_ldp_update = &update_param;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_update(lchip, nhid, (sys_nh_param_com_t*)(&nh_param)), p_usw_nh_api_master[lchip]->p_mutex);
    sys_usw_nh_set_dirty_flag(lchip, nhid, 1);
    SYS_NH_UNLOCK;

    if (update_param.is_update)
    {
        /*Update DsIP*/
        SYS_CB(SYS_CB_NHID_UPDATE_L3, lchip, &update_param);

        /*Update DsAcl*/
        SYS_CB(SYS_CB_NHID_UPDATE_ACL, lchip, &update_param);
    }

    SYS_NH_LOCK;
    sys_usw_nh_set_dirty_flag(lchip, nhid, 0);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}
int32
sys_usw_nh_remove_overlay(uint8 lchip, uint32 nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nhid = %d\n", nhid);

   if(!DRV_FROM_TMM(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_api_delete(lchip, nhid, SYS_NH_TYPE_OVERLAY), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32 sys_usw_nh_free_rsv_resource(uint8 lchip)
{
    sys_hbnh_brguc_node_info_t brguc_node_tmp;
    sys_hbnh_brguc_node_info_t *p_brguc_nhid_info = NULL;
    sys_nh_info_dsnh_t  nh_info_dsnh;
    uint32 port_id = 0;
    uint8 index = 0;
    uint32 min_index[2]={0,0x1f00};
    uint32 max_index[2]={MCHIP_CAP(SYS_CAP_PORT_NUM),0x1f00+ MCHIP_CAP(SYS_CAP_LINKAGG_GROUP_NUM)};
    uint8 gchip = 0;

    if (!DRV_FROM_AT(lchip))
    {
        return CTC_E_NOT_SUPPORT;
    }
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    sys_usw_get_gchip_id(lchip, &gchip);

    for (index = 0; index < 2; index++)
    {
        for (port_id = min_index[index]; port_id < max_index[index]; port_id++)
        {
            brguc_node_tmp.gport = CTC_MAP_LPORT_TO_GPORT(gchip, port_id);
            p_brguc_nhid_info = ctc_hash_lookup(p_usw_nh_api_master[lchip]->brguc_info.brguc_hash, &brguc_node_tmp);
            if (NULL == p_brguc_nhid_info)
            {
                continue;
            }
            sal_memset(&nh_info_dsnh,0,sizeof(nh_info_dsnh));
            CTC_ERROR_DUMP(sys_usw_nh_get_nhinfo(lchip, p_brguc_nhid_info->nhid_brguc, &nh_info_dsnh, 1));
            if (nh_info_dsnh.dsfwd1_valid)
            {
                sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_FWD1, 1, nh_info_dsnh.dsfwd1_offset);
            }
        }
    }
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

#define __ARP__
int32
sys_usw_nh_add_nexthop_mac(uint8 lchip, uint32 arp_id, ctc_nh_nexthop_mac_param_t* p_param)
{
    int32 ret = CTC_E_NONE;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_param);
    if (CTC_FLAG_ISSET(p_param->flag, CTC_NH_NEXTHOP_MAC_ECMP_IF_ARP))
    {
        if (CTC_FLAG_ISSET(p_param->flag, CTC_NH_NEXTHOP_MAC_VLAN_VALID))
        {
            CTC_MAX_VALUE_CHECK(p_param->vlan_id, CTC_MAX_VLAN_ID);
            CTC_ERROR_RETURN(sys_usw_l3if_set_ecmp_if_vlan(lchip, p_param->gport, p_param->vlan_id));
        }
        else
        {
            CTC_ERROR_RETURN(sys_usw_l3if_set_ecmp_if_vlan(lchip, p_param->gport, 0));
        }
        CTC_ERROR_RETURN(sys_usw_port_api_set_port_mac(lchip, p_param->gport, p_param->mac));
    }
    else
    {
        CTC_PTR_VALID_CHECK(p_param);
        SYS_NH_LOCK;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ARP, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_add_nexthop_mac(lchip, arp_id, p_param), p_usw_nh_api_master[lchip]->p_mutex);
        SYS_NH_UNLOCK;
    }

    return ret;
}

/**
 @brief Remove Next Hop Router Mac
*/
int32
sys_usw_nh_remove_nexthop_mac(uint8 lchip, uint32 arp_id)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ARP, 1);
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_remove_nexthop_mac(lchip, arp_id), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/**
 @brief Update Next Hop Router Mac
*/
int32
sys_usw_nh_update_nexthop_mac(uint8 lchip, uint32 arp_id, ctc_nh_nexthop_mac_param_t* p_new_param)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    CTC_PTR_VALID_CHECK(p_new_param);
    if (CTC_FLAG_ISSET(p_new_param->flag, CTC_NH_NEXTHOP_MAC_ECMP_IF_ARP))
    {
        if (CTC_FLAG_ISSET(p_new_param->flag, CTC_NH_NEXTHOP_MAC_VLAN_VALID))
        {
            CTC_VLAN_RANGE_CHECK(p_new_param->vlan_id);
            CTC_ERROR_RETURN(sys_usw_l3if_set_ecmp_if_vlan(lchip, p_new_param->gport, p_new_param->vlan_id));
        }
        else
        {
            CTC_ERROR_RETURN(sys_usw_l3if_set_ecmp_if_vlan(lchip, p_new_param->gport, 0));
        }
        CTC_ERROR_RETURN(sys_usw_port_api_set_port_mac(lchip, p_new_param->gport, p_new_param->mac));
    }
    else
    {
        sys_nh_info_dsnh_t dsnh;
        SYS_NH_LOCK;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_ARP, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_update_nexthop_mac(lchip, arp_id, p_new_param), p_usw_nh_api_master[lchip]->p_mutex);
		CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_ad(lchip, arp_id, 0xFF, 0,&dsnh),p_usw_nh_api_master[lchip]->p_mutex);
        SYS_NH_UNLOCK;
     	if(dsnh.updateAd)
   	    {
   		    dsnh.updateAd(dsnh.bind_lchip, dsnh.data, &dsnh);
   	    }
    }
    return CTC_E_NONE;
}

int32
sys_usw_nh_del_ipmc_dsnh_offset(uint8 lchip, uint16 l3ifid)
{
    sys_usw_nh_master_t* p_nh_master = NULL;
    uint32 cmd = 0;
    ds_t dsnexthop;
    uint32 l2_edit = 0;

    SYS_NH_INIT_CHECK;

    p_nh_master = g_usw_nh_master[lchip];
    SYS_NH_LOCK;
    SYS_USW_REGISTER_WB_SYNC_EN(SYS_PP_BASE(lchip), CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MCAST_L3IF, 1);
    if (p_nh_master->ipmc_dsnh_offset[l3ifid] != 0)
    {
        cmd = DRV_IOR(DsNextHop4W_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_nh_master->ipmc_dsnh_offset[l3ifid], cmd, &dsnexthop);
        if (GetDsNextHop4W(V, shareType_f, &dsnexthop) == SYS_NH_SHARE_TYPE_L2EDIT_VLAN)
        {
            l2_edit = GetDsNextHop4W(V, u1_g4_outerEditPtr_f, &dsnexthop);
            if (l2_edit != p_nh_master->rsv_l2edit_ptr)
            {
                sys_usw_nh_remove_l2edit(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_3W, l2_edit);
            }
        }
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_4W, 1,
                                         p_nh_master->ipmc_dsnh_offset[l3ifid]);
        p_nh_master->ipmc_dsnh_offset[l3ifid] = 0;

    }
    if (p_nh_master->pon_ipmc_dsnh_offset[l3ifid] != 0)
    {
        cmd = DRV_IOR(DsNextHop8W_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_nh_master->pon_ipmc_dsnh_offset[l3ifid], cmd, &dsnexthop);

        l2_edit = GetDsNextHop8W(V, innerEditPtr_f, &dsnexthop);
        sys_usw_nh_remove_l2edit(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_SWAP, l2_edit);
        sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_8W, 1,
                                         p_nh_master->pon_ipmc_dsnh_offset[l3ifid]);
        p_nh_master->pon_ipmc_dsnh_offset[l3ifid] = 0;
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_alloc_ecmp_offset(uint8 lchip, uint8 is_grp, uint8 entry_num, uint32* p_offset)
{
    sys_usw_opf_t opf;
    sys_usw_nh_master_t* p_nh_master = NULL;

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;

    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    p_nh_master = g_usw_nh_master[lchip];
    if (is_grp)
    {
        opf.pool_type = p_nh_master->ecmp_group_opf_type;
        opf.pool_index = 0;
        opf.reverse = 1;
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_opf_alloc_offset(lchip, &opf, entry_num, p_offset), p_usw_nh_api_master[lchip]->p_mutex);
    }
    else
    {
        opf.pool_type = p_nh_master->ecmp_member_opf_type;
        opf.pool_index = 0;
        opf.multiple = SYS_ECMP_MEM_HW_SUB_NUM;
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_opf_alloc_offset(lchip, &opf, entry_num, p_offset), p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_alloc_ecmp_offset_from_position(uint8 lchip, uint8 is_grp, uint8 entry_num, uint32 offset)
{
    sys_usw_opf_t opf;
    sys_usw_nh_master_t* p_nh_master = NULL;

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;

    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    p_nh_master = g_usw_nh_master[lchip];
    if (is_grp)
    {
        opf.pool_type = p_nh_master->ecmp_group_opf_type;
        opf.pool_index = 0;
        opf.reverse = 1;
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_opf_alloc_offset_from_position(lchip, &opf, entry_num, offset),
            p_usw_nh_api_master[lchip]->p_mutex);
    }
    else
    {
        opf.pool_type = p_nh_master->ecmp_member_opf_type;
        opf.pool_index = 0;
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_opf_alloc_offset_from_position(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, entry_num, offset),
            p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_free_ecmp_offset(uint8 lchip, uint8 is_grp, uint8 entry_num, uint32 offset)
{
    sys_usw_opf_t opf;
    sys_usw_nh_master_t* p_nh_master = NULL;

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;

    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    p_nh_master = g_usw_nh_master[lchip];
    if (is_grp)
    {
        opf.pool_type = p_nh_master->ecmp_group_opf_type;
        opf.pool_index = 0;
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_opf_free_offset(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, entry_num, offset), p_usw_nh_api_master[lchip]->p_mutex);
    }
    else
    {
        opf.pool_type = p_nh_master->ecmp_member_opf_type;
        opf.pool_index = 0;
        CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_opf_free_offset(SYS_MAP_LCHIP(lchip, CTC_FEATURE_NEXTHOP), &opf, entry_num, offset), p_usw_nh_api_master[lchip]->p_mutex);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

#define __ECMP__
int32
sys_usw_nh_get_current_ecmp_group_num(uint8 lchip, uint16* cur_group_num)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    *cur_group_num = g_usw_nh_master[lchip]->cur_ecmp_cnt;
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_max_ecmp_group_num(uint8 lchip, uint16* max_group_num, uint8* hecmp_en)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    *max_group_num = g_usw_nh_master[lchip]->max_ecmp_group_num;
    *hecmp_en = g_usw_nh_master[lchip]->h_ecmp_en ? 1 : 0;
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/*Notice: the function only can used by ctc layer or sys layer from other module, for nexthop module cannot use!!!!*/
int32
sys_usw_nh_get_max_ecmp(uint8 lchip, uint16* max_ecmp)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_get_max_ecmp(lchip, max_ecmp), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}


int32
sys_usw_nh_get_resolved_offset(uint8 lchip, sys_usw_nh_res_offset_type_t type, uint32* p_offset)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_offset);

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_get_resolved_offset(lchip, type, p_offset),
        p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_set_ecmp_rr_en(uint8 lchip, uint32 nh, uint8 rr_en, uint8 is_random)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    DsEcmpRrCount_m rr_count;
    DsEcmpGroup_m agg_grp;
    uint32 group_id = 0;
    sys_usw_nh_master_t* p_nh_master = NULL;
    sys_nh_info_com_t nh_temp;
    sys_nh_info_ecmp_t* ecmp_temp = NULL;
    uint8 ecmp_rr_id = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;
    sal_memset(&nh_temp, 0, sizeof(nh_temp));
    sal_memset(&rr_count, 0, sizeof(rr_count));

    SYS_NH_LOCK;
    p_nh_master = g_usw_nh_master[lchip];
    nh_temp.hdr.nh_id = nh;
    ecmp_temp = (sys_nh_info_ecmp_t*)ctc_hash_lookup(p_nh_master->nhid_hash, &nh_temp);
    if (!ecmp_temp)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, " [Nexthop] Nexthop  exist \n");
        ret = CTC_E_NOT_EXIST;
        goto error_proc;
    }
    if ((ecmp_temp->type != CTC_NH_ECMP_TYPE_STATIC && rr_en) || (ecmp_temp->type == CTC_NH_ECMP_TYPE_STATIC && !rr_en))
    {
        ret = CTC_E_INVALID_CONFIG;
        goto error_proc;
    }
    group_id = ecmp_temp->ecmp_group_id;
    ecmp_rr_id = group_id;
    if (DRV_FROM_TMM(lchip) && p_nh_master->h_ecmp_en)
    {
        ecmp_rr_id = group_id - ((MCHIP_CAP(SYS_CAP_NH_ECMP_GROUP_ID_NUM) + 1) / 2);
    }
    /* 1. prepare DsEcmpRrCount profile */
    if ((ecmp_rr_id >= SYS_NH_ECMP_RR_COUNT) || (DRV_FROM_TMM(lchip) && ecmp_temp->h_ecmp_en))
    {
        ret = CTC_E_INVALID_CONFIG;
        goto error_proc;
    }
    SetDsEcmpRrCount(V, randomRrEn_f, &rr_count, is_random?1:0);
    SetDsEcmpRrCount(V, memberNum_f, &rr_count, (ecmp_temp->valid_cnt-1));
    cmd = DRV_IOW(DsEcmpRrCount_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, ecmp_rr_id, cmd, &rr_count),ret, error_proc);

    /* 2. modify to rr mode and assign RrCount profile or modify to static mode*/
    cmd = DRV_IOR(DsEcmpGroup_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, group_id, cmd, &agg_grp),ret, error_proc);
    SetDsEcmpGroup(V, runningMode_f, &agg_grp, rr_en?2:0);
    cmd = DRV_IOW(DsEcmpGroup_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, group_id, cmd, &agg_grp),ret, error_proc);
    /* 3. modify the soft table*/
    ecmp_temp->type = rr_en? (is_random? CTC_NH_ECMP_TYPE_RANDOM_RR : CTC_NH_ECMP_TYPE_RR) : CTC_NH_ECMP_TYPE_STATIC;
    ecmp_temp->random_rr_en = is_random;
error_proc:
    SYS_NH_UNLOCK;
    return ret;
}

#define __INTERNAL_API__

int32
sys_usw_nh_set_bridge_inner_mode(uint8 lchip, uint8 mode)
{
    sys_usw_nh_master_t* p_nh_master = NULL;
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    p_nh_master = g_usw_nh_master[lchip];
    if (DRV_FROM_TMM(lchip))
    {
        uint32 value = 0;
        uint32 cmd = 0;
        ds1_t ds;

        cmd = DRV_IOR(EpePktProcCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN_WITH_UNLOCK(DRV_IOCTL(lchip, 0, cmd, ds), p_usw_nh_api_master[lchip]->p_mutex);
        if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
        {
            drv_get_field(lchip, EpePktProcCtl_t, EpePktProcCtl_bridgeInnerMode_f, ds, &value);
            p_nh_master->bridge_inner_mode = value;
        }
        else
        {

            SetEpePktProcCtl(V, bridgeInnerMode_f, ds, mode ? 0x1 : 0x0);
            cmd = DRV_IOW(EpePktProcCtl_t, DRV_ENTRY_FLAG);
            CTC_ERROR_RETURN_WITH_UNLOCK(DRV_IOCTL(lchip, 0, cmd, ds), p_usw_nh_api_master[lchip]->p_mutex);
            p_nh_master->bridge_inner_mode = mode ? 1 :0;

            if (DRV_FROM_AT(lchip))
            {
                cmd = DRV_IOR(EpeNextHopCtl_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN_WITH_UNLOCK(DRV_IOCTL(lchip, 0, cmd, ds), p_usw_nh_api_master[lchip]->p_mutex);
                SetEpeNextHopCtl(V, isLeafShareMatrix_0_shareInfo_f, &ds, 0x0);
                SetEpeNextHopCtl(V, isLeafShareMatrix_1_shareInfo_f, &ds, mode ? 0x2 : 0x1);
                cmd = DRV_IOW(EpeNextHopCtl_t, DRV_ENTRY_FLAG);
                CTC_ERROR_RETURN_WITH_UNLOCK(DRV_IOCTL(lchip, 0, cmd, ds), p_usw_nh_api_master[lchip]->p_mutex);
            }
        }
    }

    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}


int32
sys_usw_nh_map_entry_type(uint8 lchip, sys_api_nh_entry_type_t type, sys_nh_entry_table_type_t* entry_type)
{
    switch (type)
    {
        case SYS_API_NH_DSFWD:
            *entry_type = SYS_NH_ENTRY_TYPE_FWD;
            break;
        case SYS_API_NH_DSFWD_HALF:
            *entry_type = SYS_NH_ENTRY_TYPE_FWD_HALF;
            break;
        case SYS_API_NH_DSMET:
            *entry_type = SYS_NH_ENTRY_TYPE_MET;
            break;
        case SYS_API_NH_L2EDIT:
            *entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_FROM;
            break;
        case SYS_API_NH_NEXTHOP_4W:
            *entry_type = SYS_NH_ENTRY_TYPE_NEXTHOP_4W;
            break;
        case SYS_API_NH_L3EDIT:
            *entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_FROM;
            break;
        case SYS_API_NH_L3EDIT_SPME:
            *entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_SPME;
            break;
        case SYS_API_NH_L2EDIT_OUTER_4W:
            *entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_4W;
            break;
        case SYS_API_NH_LOGIC_DEST_PORT:
            *entry_type = SYS_NH_ENTRY_TYPE_LOGIC_DEST_PORT;
            break;
        case SYS_API_NH_DSFWD1:
            *entry_type = SYS_NH_ENTRY_TYPE_FWD1;
            break;
        case SYS_API_NH_DSFWD_HALF1:
            *entry_type = SYS_NH_ENTRY_TYPE_FWD_HALF1;
            break;
        case SYS_API_NH_L2EDIT_INNER:
            *entry_type = SYS_NH_ENTRY_TYPE_L2EDIT_INNER_FROM;
            break;
        case SYS_API_NH_L3EDIT_INNER:
            *entry_type = SYS_NH_ENTRY_TYPE_L3EDIT_INNER_FROM;
            break;
        case SYS_API_NH_DSMET_RSVED:
            *entry_type = SYS_NH_ENTRY_TYPE_MET_RSVED;
            break;
        default:
            return CTC_E_INVALID_PARAM;
            break;
    }
    return CTC_E_NONE;
}

int32
sys_usw_nh_alloc_from_position(uint8 lchip, sys_api_nh_entry_type_t type, uint32 entry_num, uint32 offset)
{
    sys_nh_entry_table_type_t entry_type = 0;
    SYS_NH_INIT_CHECK;
    CTC_ERROR_RETURN(sys_usw_nh_map_entry_type(lchip, type, &entry_type));
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_offset_alloc_from_position(lchip, entry_type, entry_num, offset),
        p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_alloc(uint8 lchip, sys_api_nh_entry_type_t type, uint32 entry_num, uint32* p_offset)
{
    sys_nh_entry_table_type_t entry_type = 0;
    SYS_NH_INIT_CHECK;
    CTC_ERROR_RETURN(sys_usw_nh_map_entry_type(lchip, type, &entry_type));
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_offset_alloc(lchip, entry_type, entry_num, p_offset), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}


int32
sys_usw_nh_free(uint8 lchip, sys_api_nh_entry_type_t type, uint32 entry_num, uint32 offset)
{
    sys_nh_entry_table_type_t entry_type = 0;
    SYS_NH_INIT_CHECK;
    CTC_ERROR_RETURN(sys_usw_nh_map_entry_type(lchip, type, &entry_type));
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_offset_free(lchip, entry_type, entry_num, offset), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_add_dsfwd(uint8 lchip, sys_nh_param_dsfwd_t* p_dsfwd_param)
{
    CTC_PTR_VALID_CHECK(p_dsfwd_param);
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_write_entry_dsfwd(lchip, p_dsfwd_param), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_update_dsfwd(uint8 lchip, sys_nh_update_dsfwd_t* p_update_param)
{
    CTC_PTR_VALID_CHECK(p_update_param);
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_update_entry_dsfwd(lchip, p_update_param),
        p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;

}

int32
sys_usw_nh_add_dsmet(uint8 lchip, sys_nh_param_dsmet_t* p_met_param, uint8 in_cb)
{
    sys_met_t dsmet;
    int32 ret = 0;

    CTC_PTR_VALID_CHECK(p_met_param);
    SYS_NH_INIT_CHECK;

    sal_memset(&dsmet, 0, sizeof(sys_met_t));

    if (!in_cb)
    {
        SYS_NH_LOCK;
    }
    dsmet.dest_id = p_met_param->dest_id;
    dsmet.remote_chip = p_met_param->remote_chip;
    dsmet.end_local_rep = p_met_param->end_local_rep;
    dsmet.next_met_entry_ptr = p_met_param->next_met_entry_ptr;
    dsmet.next_hop_ptr = p_met_param->next_hop_ptr;
    dsmet.aps_bridge_en = p_met_param->aps_bridge_en;
    dsmet.is_destmap_profile = p_met_param->is_destmap_profile;
    dsmet.is_agg = p_met_param->is_linkagg;
    dsmet.next_hop_ext = p_met_param->next_ext;

    ret = sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_MET, p_met_param->met_offset, &dsmet);

    if (!in_cb)
    {
        SYS_NH_UNLOCK;
    }

    return ret;
}

int32
sys_usw_nh_get_dsmet(uint8 lchip, uint32 met_offset, sys_nh_param_dsmet_t* dsmet_param)
{
    ds0_t ds;
    uint32 cmd = 0;
    uint8 met_slim = DRV_TABLE_MAX_INDEX(lchip, DsMetEntrySlim1X_t)? 1 : 0;
    uint32 tbl_id = DRV_FROM_AT(lchip)? (met_slim? DsMetEntrySlim1X_t : DsMetEntry1X_t) : DsMetEntry3W_t;

    SYS_NH_LOCK;
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, met_offset, cmd, &ds);
    if (DRV_FROM_AT(lchip))
    {
        if (met_slim)
        {
            dsmet_param->next_met_entry_ptr = GetDsMetEntrySlim1X(V, nextMetEntryPtr_f, &ds);
            dsmet_param->dest_id = GetDsMetEntrySlim1X(V, ucastId_f, &ds);
            dsmet_param->next_hop_ptr = GetDsMetEntrySlim1X(V, replicationCtl_f, &ds);
            dsmet_param->remote_chip = GetDsMetEntrySlim1X(V, remoteChip_f, &ds);
        }
        else
        {
            dsmet_param->next_met_entry_ptr = GetDsMetEntry1X(V, nextMetEntryPtr_f, &ds);
            dsmet_param->dest_id = GetDsMetEntry1X(V, ucastId_f, &ds);
            dsmet_param->next_hop_ptr = GetDsMetEntry1X(V, replicationCtl_f, &ds);
            dsmet_param->remote_chip = GetDsMetEntry1X(V, remoteChip_f, &ds);
        }
        CTC_BIT_UNSET(dsmet_param->next_hop_ptr, 18);
    }
    else
    {
        dsmet_param->next_met_entry_ptr = GetDsMetEntry3W(V, nextMetEntryPtr_f, &ds);
        dsmet_param->dest_id = GetDsMetEntry3W(V, ucastId_f, &ds);
        dsmet_param->next_hop_ptr = (DRV_IS_TMM(lchip) || DRV_IS_TMG(lchip))?(GetDsMetEntry3W(V, replicationCtl_f, &ds)&0x3FFFF):(GetDsMetEntry3W(V, replicationCtl_f, &ds)>>5);
        dsmet_param->remote_chip = GetDsMetEntry3W(V, remoteChip_f, &ds);
    }

    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}
int32
sys_usw_nh_update_dsmet(uint8 lchip, uint32 met_offset, sys_nh_param_dsmet_t* dsmet_param)
{
    ds0_t ds;
    uint32 cmd = 0;
    uint8 met_slim = DRV_TABLE_MAX_INDEX(lchip, DsMetEntrySlim1X_t)? 1 : 0;
    uint32 tbl_id = DRV_FROM_AT(lchip)? (met_slim? DsMetEntrySlim1X_t : DsMetEntry1X_t) : DsMetEntry3W_t;
    uint32 next_hop_ptr = dsmet_param->next_hop_ptr | (1 << 18);

    SYS_NH_LOCK;

    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, met_offset, cmd, &ds);

    if (DRV_FROM_AT(lchip))
    {
        if (dsmet_param->next_met_entry_ptr_valid)
        {
            met_slim? SetDsMetEntrySlim1X(V, nextMetEntryPtr_f,  &ds, dsmet_param->next_met_entry_ptr)
                    : SetDsMetEntry1X(V, nextMetEntryPtr_f,  &ds, dsmet_param->next_met_entry_ptr);
        }
        if (dsmet_param->next_hop_ptr_valid)
        {
            /* 2 == dsmet_param->next_hop_ptr_valid, use exception_id replace next_hop_ptr */
            next_hop_ptr = (2 == dsmet_param->next_hop_ptr_valid) ? dsmet_param->next_hop_ptr : next_hop_ptr;
            met_slim? SetDsMetEntrySlim1X(V, replicationCtl_f,  &ds, next_hop_ptr)
                    : SetDsMetEntry1X(V, replicationCtl_f,  &ds, next_hop_ptr);
        }
        if (dsmet_param->dest_id_valid)
        {
            met_slim? SetDsMetEntrySlim1X(V, ucastId_f,  &ds, dsmet_param->dest_id)
                    : SetDsMetEntry1X(V, ucastId_f,  &ds, dsmet_param->dest_id);
        }
    }
    else
    {
        if (dsmet_param->next_met_entry_ptr_valid)
        {
            SetDsMetEntry3W(V, nextMetEntryPtr_f,  &ds, dsmet_param->next_met_entry_ptr);
        }
        if (dsmet_param->next_hop_ptr_valid)
        {
            SetDsMetEntry3W(V, replicationCtl_f,  &ds, (DRV_IS_TMM(lchip) || DRV_IS_TMG(lchip))?((1 << 18) | next_hop_ptr):(next_hop_ptr << 5));
        }
        if (dsmet_param->dest_id_valid)
        {
            SetDsMetEntry3W(V, ucastId_f,  &ds, dsmet_param->dest_id);
        }
    }
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, met_offset, cmd, &ds);

    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_set_vpws_vpnid(uint8 lchip, uint32 nhid, uint32 vpn_id)
{

    DsFwd_m dsfwd;
    int32  ret = 0;
    sys_nh_info_com_t* p_nh_com_info;
    uint32 dsfwd_offset = 0;

    sal_memset(&dsfwd, 0, sizeof(dsfwd));
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, (sys_nh_info_com_t**)&p_nh_com_info), ret, error_proc);
    if (CTC_FLAG_ISSET(p_nh_com_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LEN_ADJUST_EN))
    {
        ret = CTC_E_INVALID_CONFIG;
        goto error_proc;
    }

    dsfwd_offset = p_nh_com_info->hdr.dsfwd_offset;

    CTC_ERROR_GOTO(sys_usw_nh_get_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD, dsfwd_offset, &dsfwd), ret, error_proc);
    if (GetDsFwd(V, isHalf_f, &dsfwd))
    {
        ret =  CTC_E_INVALID_CONFIG;
        goto error_proc;
    }
    SetDsFwd(V, vpwsFidEn_f, &dsfwd, 1);
    SetDsFwd(V, truncateLenProfId_f, &dsfwd, (vpn_id&0xf));
    SetDsFwd(V, truncateLenProfIdType_f, &dsfwd, ((vpn_id>>4)&0x1));
    SetDsFwd(V, serviceId_f, &dsfwd, ((vpn_id>>5)&0x1ff));

    CTC_ERROR_GOTO(sys_usw_nh_set_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD, dsfwd_offset, &dsfwd), ret, error_proc);

    if (DRV_FROM_AT(lchip) && p_nh_com_info->hdr.dsfwd1_offset)
    {
        dsfwd_offset = p_nh_com_info->hdr.dsfwd1_offset;
        CTC_ERROR_GOTO(sys_usw_nh_get_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD1, dsfwd_offset, &dsfwd), ret, error_proc);
        SetDsFwd(V, vpwsFidEn_f, &dsfwd, 1);
        SetDsFwd(V, truncateLenProfId_f, &dsfwd, (vpn_id&0xf));
        SetDsFwd(V, truncateLenProfIdType_f, &dsfwd, ((vpn_id >> 4)&0x1));
        SetDsFwd(V, serviceId_f, &dsfwd, ((vpn_id >> 5)&0x1ff));

        CTC_ERROR_GOTO(sys_usw_nh_set_asic_table(lchip, SYS_NH_ENTRY_TYPE_FWD1, dsfwd_offset, &dsfwd), ret, error_proc);
    }
error_proc:
    SYS_NH_UNLOCK;

    return ret;
}


int32
sys_usw_nh_traverse_nh_db(uint8 lchip, hash_traversal_fn fn, void* data)
{
    SYS_NH_INIT_CHECK;

    ctc_hash_traverse(g_usw_nh_master[lchip]->nhid_hash, fn, data);

    return CTC_E_NONE;
}


int32
sys_usw_nh_check_glb_met_offset(uint8 lchip, uint32 start_offset, uint32 entry_num,
                                      bool should_not_inuse)
{
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_check_glb_met_offset(lchip, start_offset, entry_num, should_not_inuse), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}


int32
sys_usw_nh_set_glb_met_offset(uint8 lchip, uint32 start_offset, uint32 entry_num, bool is_set)
{
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_set_glb_met_offset(lchip, start_offset, entry_num, is_set), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_mcast_profile_offset(uint8 lchip, uint32 nh_id, uint32* met_offset)
{
    int32  ret = CTC_E_NONE;
    sys_nh_info_com_t* p_nh_com_info = NULL;
    sys_nh_info_mcast_t* p_mcast_db = NULL;
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;

    CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, nh_id, (sys_nh_info_com_t**)&p_nh_com_info), ret, error_proc);
    if (p_nh_com_info->hdr.nh_entry_type != SYS_NH_TYPE_MCAST)
    {
        ret = CTC_E_INVALID_CONFIG;
        goto error_proc;
    }
    p_mcast_db = (sys_nh_info_mcast_t*)p_nh_com_info;
    if (!CTC_FLAG_ISSET(p_mcast_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_MCAST_PROFILE))
    {
        ret = CTC_E_INVALID_CONFIG;
        goto error_proc;
    }
    *met_offset = p_mcast_db->basic_met_offset;

error_proc:
    SYS_NH_UNLOCK;

    return ret;
}


int32
sys_usw_nh_get_fatal_excp_dsnh_offset(uint8 lchip, uint32* p_offset)
{
    CTC_PTR_VALID_CHECK(p_offset);

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_PTR_VALID_CHECK(p_offset);
    SYS_NH_INIT_CHECK;
    //SYS_NH_LOCK;
    *p_offset = g_usw_nh_master[lchip]->fatal_excp_base;
    //SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_max_external_nhid(uint8 lchip, uint32* nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;
    *nhid = g_usw_nh_master[lchip]->max_external_nhid;
    return CTC_E_NONE;
}

int32/*bit 31:is_8w; bit30: bypass_ingress_edit*/
sys_usw_nh_get_mirror_info_by_nhid(uint8 lchip, uint32 nhid, uint32* dsnh_offset, uint32* gport, bool enable)
{
    sys_nh_info_com_t* p_nhinfo;
    uint8  gchip = 0;

    CTC_PTR_VALID_CHECK(dsnh_offset);
    CTC_PTR_VALID_CHECK(gport);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;

    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, &p_nhinfo), p_usw_nh_api_master[lchip]->p_mutex);

    switch (p_nhinfo->hdr.nh_entry_type)
    {
    case SYS_NH_TYPE_RSPAN:
        {
            *gport = 0xFFFF;
            *dsnh_offset = p_nhinfo->hdr.dsnh_offset;
        }
        break;

    case SYS_NH_TYPE_MCAST:
        {
            *gport = 0;
            *dsnh_offset = DRV_FROM_TMM(lchip)?0:SYS_DSNH_INDEX_FOR_NONE;
        }
        break;

    case SYS_NH_TYPE_IP_TUNNEL:
        {
            sys_nh_info_ip_tunnel_t* p_ip_tunnel = (sys_nh_info_ip_tunnel_t*)p_nhinfo;

            *gport = p_ip_tunnel->gport;
            *dsnh_offset = p_nhinfo->hdr.dsnh_offset;

            if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
            {
                CTC_BIT_SET(*dsnh_offset, 31);
            }

        }
        break;

    case  SYS_NH_TYPE_TOCPU:
        sys_usw_get_gchip_id(lchip, &gchip);
        *gport = CTC_GPORT_RCPU(gchip);
        *dsnh_offset = SYS_DSNH_INDEX_FOR_NONE;
        break;

    case SYS_NH_TYPE_ILOOP:
        {
            sys_nh_info_special_t* p_nh_spec_info = (sys_nh_info_special_t*)p_nhinfo;

            *gport = p_nh_spec_info->dest_gport;
            *dsnh_offset = p_nh_spec_info->hdr.dsnh_offset;
        }
        break;

    case SYS_NH_TYPE_MISC:
        {
            sys_nh_info_misc_t* p_nh_misc_info = (sys_nh_info_misc_t*)p_nhinfo;
            *gport = p_nh_misc_info->gport;
            *dsnh_offset = p_nh_misc_info->hdr.dsnh_offset;

            if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
            {
                CTC_BIT_SET(*dsnh_offset, 31);
            }

        }
        break;

    case  SYS_NH_TYPE_ECMP:
        {
            sys_nh_info_ecmp_t* p_ecmp = (sys_nh_info_ecmp_t*)p_nhinfo;
            *gport = p_ecmp->gport;
            *dsnh_offset = p_nhinfo->hdr.dsnh_offset;
            CTC_BIT_SET(*dsnh_offset, 31);
        }
        break;
    case SYS_NH_TYPE_BRGUC:
        {
            sys_nh_info_brguc_t* p_brguc = (sys_nh_info_brguc_t*)p_nhinfo;
            *gport = p_brguc->dest_gport;
            *dsnh_offset = p_nhinfo->hdr.dsnh_offset;
            CTC_BIT_SET(*dsnh_offset, 31);
        }
        break;
    default:
        SYS_NH_UNLOCK;
        return CTC_E_INVALID_PARAM;

    }

    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE) ||
        (p_nhinfo->hdr.nh_entry_type == SYS_NH_TYPE_ECMP && ((sys_nh_info_ecmp_t*)p_nhinfo)->type == CTC_NH_ECMP_TYPE_XERSPAN && g_usw_nh_master[lchip]->pkt_nh_edit_mode))
    {
        CTC_BIT_SET(*dsnh_offset, 30);
    }

    SYS_NH_UNLOCK;
    return CTC_E_NONE;

}

int32
sys_usw_nh_get_reflective_dsfwd_offset(uint8 lchip, uint32* p_dsfwd_offset)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    *p_dsfwd_offset = g_usw_nh_master[lchip]->reflective_resolved_dsfwd_offset;
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/*Notice: This function donot use Lock, nexthop&Aps will call each other, Lock have no meaning and will cause deadlock*/
int32
sys_usw_nh_map_destmap_to_port(uint8 lchip, uint32 destmap, uint32 *gport)
{
    uint32 cmd = 0;
    uint32 arp_destmap = 0;
    uint16 destmap_profile = 0;

    SYS_NH_INIT_CHECK;

    if ((destmap >> 17)&0x01)
    {
        destmap_profile = (destmap&0xFFFF);
        cmd = DRV_IOR(DsDestMapProfileUc_t, DsDestMapProfileUc_destMap_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, destmap_profile, cmd, &arp_destmap));
        if (arp_destmap == 0xffff)
        {
            uint8 gchip = 0;
            /*Arp to cpu*/
            sys_usw_get_gchip_id(lchip, &gchip);
            *gport = CTC_GPORT_RCPU(gchip);
        }
        else
        {
            *gport = SYS_USW_DESTMAP_TO_DRV_GPORT(arp_destmap);
            *gport = SYS_MAP_DRV_GPORT_TO_CTC_GPORT(*gport);
        }

    }
    else
    {
        *gport = SYS_USW_DESTMAP_TO_DRV_GPORT(destmap);
        *gport = SYS_MAP_DRV_GPORT_TO_CTC_GPORT(*gport);
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_set_bpe_en(uint8 lchip, bool enable)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;

    /*0. DsNexthop for bpe ecid transparent*/
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_dsnh_init_for_bpe_transparent(lchip,
             &(g_usw_nh_master[lchip]->sys_nh_resolved_offset[SYS_NH_RES_OFFSET_TYPE_BPE_TRANSPARENT_NH])), p_usw_nh_api_master[lchip]->p_mutex);

    g_usw_nh_master[lchip]->bpe_en = enable;
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_bpe_en(uint8 lchip, uint8* enable)
{
    SYS_NH_INIT_CHECK;
    *enable = g_usw_nh_master[lchip]->bpe_en;
    return CTC_E_NONE;
}

int32
sys_usw_nh_set_bpe_mc_en(uint8 lchip, uint8 enable)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    g_usw_nh_master[lchip]->bpe_mc_en = enable;
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}
/*The function is called during fdb init, do not using lock*/
int32
sys_usw_nh_vxlan_vni_init(uint8 lchip)
{
    SYS_NH_INIT_CHECK;
    CTC_ERROR_RETURN(_sys_usw_nh_vxlan_vni_init(lchip));
    return CTC_E_NONE;
}

int32
sys_usw_nh_set_vxlan_mode(uint8 lchip, uint8 mode)
{
    uint32 cmd = 0;
    uint32 val = 0;
    int32 ret = CTC_E_NONE;

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    if ((SYS_GET_CHIP_VERSION != SYS_CHIP_SUB_VERSION_A) && DRV_IS_TSINGMA(lchip))
    {
        val = mode?1:0;
        cmd = DRV_IOW(QWriteCtl_t, QWriteCtl_queueEntryCarryLogicDestPort_f);
        CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, cmd, &val), ret, done);
        cmd = DRV_IOW(QMgrCtl_t, QMgrCtl_queueEntryCarryLogicDestPort_f);
        CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, cmd, &val), ret, done);
    }
    g_usw_nh_master[lchip]->vxlan_mode = mode;

done:
    SYS_NH_UNLOCK;
    return ret;
}

bool
sys_usw_nh_is_ipmc_logic_rep_enable(uint8 lchip)
{
    int32 ret = 0;

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    ret = _sys_usw_nh_is_ipmc_logic_rep_enable(lchip);
    SYS_NH_UNLOCK;

    return ret ? TRUE : FALSE;
}


int32
sys_usw_nh_set_ipmc_logic_replication(uint8 lchip, uint8 enable)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_set_ipmc_logic_replication(lchip, enable), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_mcast_nh(uint8 lchip, uint32 group_id, uint32* nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(nhid);

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_get_mcast_nh(lchip, group_id, nhid, NULL), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

/* For AT PP mode, get mcast nexthop id by mcast group id, and then set or unset pp bitmap in mcast db */
int32
sys_usw_nh_set_mcast_ppbmp(uint8 lchip, uint32 group_id, uint32 set_flag)
{
    sys_nh_info_mcast_t* p_mcast_db = NULL;
    uint32 nhid = 0;
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_NH_INIT_CHECK;

    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_get_mcast_nh(lchip, group_id, &nhid, (void**)&p_mcast_db), p_usw_nh_api_master[lchip]->p_mutex);
    if (set_flag == 1)
    {
        CTC_BIT_SET(p_mcast_db->pp_bmp, (lchip - SYS_PP_BASE(lchip)));
    }
    else
    {
        CTC_BIT_UNSET(p_mcast_db->pp_bmp, (lchip - SYS_PP_BASE(lchip)));
    }

    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}


int32
sys_usw_nh_update_dot1ae(uint8 lchip, void* param)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(sys_usw_nh_ip_tunnel_update_dot1ae(lchip, param), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_set_l3edit_natsa(uint8 lchip, uint32* ipsa, uint16 src_port, uint32* p_offset,
                             uint8 double_nat, uint8 is_ipv6, uint8 masklen, uint8 is_add)
{
    uint8 edit_type = SYS_NH_ENTRY_TYPE_L3EDIT_NAT_8W;
    void* p_dsl3edit = NULL;
    sys_dsl3edit_nat8w_t   nat_8w;
    sys_dsl3edit_nat4w_t   nat_4w;
    uint32 tbl_id = 0;
    uint16 snat_edit_base = 0;

    if (is_ipv6)
    {
        sal_memset(&nat_8w, 0, sizeof(sys_dsl3edit_nat8w_t));
        nat_8w.ds_type = SYS_NH_DS_TYPE_L3EDIT;
        sal_memcpy(nat_8w.ipda, ipsa, sizeof(ipv6_addr_t));
        if (masklen)
        {
            edit_type = SYS_NH_ENTRY_TYPE_L3EDIT_NAT_V6_16W;
            nat_8w.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_RWIP6);
            nat_8w.replace_ip_sa = is_add? 2: 0;
            IPV6_LEN_TO_MASK(nat_8w.mask,masklen);
            nat_8w.sub_net = 1;
        }
        else
        {
            edit_type = SYS_NH_ENTRY_TYPE_L3EDIT_NAT_V6_8W;
            nat_8w.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_RWIP62X);
            nat_8w.replace_ip_sa = is_add? 1: 0;
        }
        nat_8w.replace_l4_src_port = src_port? 1 : 0;
        nat_8w.nat_sa = 1;
        p_dsl3edit = (void*)&nat_8w;
    }
    else if (!DRV_FROM_AT(lchip) || 0 != masklen)
    {
        sal_memset(&nat_8w, 0, sizeof(sys_dsl3edit_nat8w_t));
        edit_type = SYS_NH_ENTRY_TYPE_L3EDIT_NAT_8W;
        nat_8w.ds_type = SYS_NH_DS_TYPE_L3EDIT;
        nat_8w.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_RWIP4);
        nat_8w.ipda[0] = ipsa[0];
        IPV4_LEN_TO_MASK(nat_8w.mask[0],masklen);
        nat_8w.sub_net = 1;
        nat_8w.replace_ip_sa = ipsa[0]? 1 : 0;
        nat_8w.l4_src_port = (DRV_FROM_AT(lchip)) ? 0 : src_port;    /* AT use XDATA carry l4 port */
        nat_8w.replace_l4_src_port = src_port? 1 : 0;
        nat_8w.nat_sa = 1;
        p_dsl3edit = (void*)&nat_8w;
    }
    else
    {
        sal_memset(&nat_4w, 0, sizeof(sys_dsl3edit_nat4w_t));
        edit_type = SYS_NH_ENTRY_TYPE_L3EDIT_NAT_4W;
        nat_4w.ds_type = SYS_NH_DS_TYPE_L3EDIT;
        nat_4w.l3_rewrite_type = DRV_ENUM(DRV_L3EDITTYPE_RWIP41X);
        nat_4w.ip = ipsa[0];
        nat_4w.replace_ip_sa = ipsa[0]? 1 : 0;
        nat_4w.replace_l4_src_port = src_port? 1 : 0;
        nat_4w.nat_sa = 1;
        p_dsl3edit = (void*)&nat_4w;
    }

    tbl_id = DRV_IS_AT(lchip) ? DsL3EditRwIp41X0_t : DsL3EditRwIp41X_t;
    snat_edit_base = (DRV_TABLE_MAX_INDEX(lchip, tbl_id) > SYS_SNAT_EDIT_PTR_BASE)? /*snatEditPtr(13,0)*/
                  (DRV_TABLE_MAX_INDEX(lchip, tbl_id) - SYS_SNAT_EDIT_PTR_BASE):0;
    if (is_add)
    {
        CTC_ERROR_RETURN(sys_usw_nh_add_l3edit_tunnel(lchip, p_dsl3edit, edit_type + SYS_NH_TYPE_STEP_TO_INNER, p_offset));
        if(*p_offset <= snat_edit_base)
        {
            sys_usw_nh_remove_l3edit_tunnel(lchip, edit_type + SYS_NH_TYPE_STEP_TO_INNER, *p_offset);
            return CTC_E_NO_RESOURCE;
        }
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_nh_remove_l3edit_tunnel(lchip, edit_type + SYS_NH_TYPE_STEP_TO_INNER, *p_offset));
    }
    return CTC_E_NONE;
}

int32
sys_usw_nh_wb_restore_edit(uint8 lchip, uint8 entry_type, uint32 edit_ptr)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_wb_restore_edit(lchip, entry_type, edit_ptr), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_add_l3edit_natsa(uint8 lchip, uint32* ipsa, uint16 src_port, uint32* p_offset,
                            uint8 double_nat, uint8 is_ipv6, uint8 masklen)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_set_l3edit_natsa(lchip, ipsa, src_port, p_offset, double_nat, is_ipv6, masklen, 1),
                                                                    p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_remove_l3edit_natsa(uint8 lchip, uint32* ipsa, uint16 src_port, uint32 offset,
                               uint8 double_nat, uint8 is_ipv6, uint8 masklen)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_set_l3edit_natsa(lchip, ipsa, src_port, &offset, double_nat, is_ipv6, masklen, 0),
                                                                    p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_get_rsv_iloop(uint8 lchip, uint8 dp_id,  uint32* nhid)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    if (nhid != NULL)
    {
        *nhid = g_usw_nh_master[lchip]->rsv_iloop_nh+(dp_id%2);
    }
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}


int32
sys_usw_nexthop_dump_db(uint8 lchip, sal_file_t p_f, ctc_global_dump_db_t* p_dump_param)
{
    int32 ret = CTC_E_NONE;

    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    ret = _sys_usw_nexthop_dump_db(lchip, p_f,p_dump_param);
    SYS_NH_UNLOCK;

    return ret;
}

int32
sys_usw_nh_get_nh_resource(uint8 lchip, sys_api_nh_entry_type_t type, uint32* used_count)
{
    uint32 entry_type = 0;
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(used_count);
    CTC_ERROR_RETURN(sys_usw_nh_map_entry_type(lchip, type, &entry_type));
    SYS_NH_LOCK;
    CTC_ERROR_RETURN_WITH_UNLOCK(_sys_usw_nh_get_nh_resource(lchip, entry_type, used_count), p_usw_nh_api_master[lchip]->p_mutex);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_met_ext_mode(uint8 lchip, uint8* met_ext_mode)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(met_ext_mode);
    SYS_NH_LOCK;
    *met_ext_mode = g_usw_nh_master[lchip]->met_ext_mode;
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}


int32
sys_usw_nh_set_max_hecmp(uint8 lchip, uint32 max_num)
{
    uint32 cmd = 0;
    uint32 field_value = 0;
    IpeFwdReserved_m fwd_rsv;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    CTC_VALUE_RANGE_CHECK(max_num, 1, SYS_ECMP_MAX_HECMP_MEM);
    SYS_NH_INIT_CHECK;

    if (!(DRV_IS_TSINGMA(lchip) && (SYS_GET_CHIP_VERSION != SYS_CHIP_SUB_VERSION_A)))
    {
        return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_LOCK;

    g_usw_nh_master[lchip]->hecmp_mem_num = max_num;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MASTER, 1);
    cmd = DRV_IOR(IpeFwdReserved_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN_WITH_UNLOCK(DRV_IOCTL(lchip, 0, cmd, &fwd_rsv), p_usw_nh_api_master[lchip]->p_mutex);
    field_value = GetIpeFwdReserved(V, reserved_f, &fwd_rsv);
    field_value &= 0xfffffe3f;
    field_value |= ((max_num&0x7) << 6);
    SetIpeFwdReserved(V, reserved_f, &fwd_rsv, field_value);
    cmd = DRV_IOW(IpeFwdReserved_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN_WITH_UNLOCK(DRV_IOCTL(lchip, 0, cmd, &fwd_rsv), p_usw_nh_api_master[lchip]->p_mutex);

    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_max_hecmp(uint8 lchip, uint32* max_ecmp)
{
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    SYS_NH_INIT_CHECK;
    if (!(DRV_IS_TSINGMA(lchip) && (SYS_GET_CHIP_VERSION != SYS_CHIP_SUB_VERSION_A)))
    {
        return CTC_E_NOT_SUPPORT;
    }

    SYS_NH_LOCK;
    *max_ecmp = g_usw_nh_master[lchip]->hecmp_mem_num;
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}
int32
sys_usw_nh_set_reflective_brg_en(uint8 lchip, uint8 enable)
{
    SYS_NH_INIT_CHECK;
    SYS_NH_LOCK;
    g_usw_nh_master[lchip]->reflective_brg_en = enable ?1:0;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MASTER, 1);
    SYS_NH_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_nh_init_twamp_rsv_nh(uint8 lchip)
{
    int32 ret = 0;
    uint32 l3_edit_offset;
    ctc_misc_nh_flex_edit_param_t edit_param;
    sys_nexthop_t dsnh;

    SYS_NH_INIT_CHECK;
    if(DRV_FROM_TMM(lchip))
    {
        return CTC_E_NONE;
    }

    SYS_NH_LOCK;
    CTC_ERROR_GOTO(sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_OF_6W, 1, &l3_edit_offset), ret, end_0);

    sal_memset(&edit_param, 0, sizeof(edit_param));
    CTC_SET_FLAG(edit_param.flag, CTC_MISC_NH_FLEX_EDIT_UPDATE_UDP_CHKSUM);
    edit_param.packet_type = CTC_MISC_NH_PACKET_TYPE_UDPORTCP;
    edit_param.dscp_select = CTC_NH_DSCP_SELECT_NONE;
    CTC_ERROR_GOTO(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_L3EDIT_OF_6W, l3_edit_offset, &edit_param), ret, end_0);

    sal_memset(&dsnh, 0, sizeof(dsnh));
    dsnh.offset = SYS_NH_BUILD_INT_OFFSET(SYS_DSNH4WREG_INDEX_FOR_TWAMP_UPD_CHKSUM);
    dsnh.payload_operation = SYS_NH_OP_NONE;
    dsnh.share_type = SYS_NH_SHARE_TYPE_L23EDIT;
    dsnh.inner_edit_ptr_type = 1;
    dsnh.inner_edit_ptr = l3_edit_offset;
    CTC_ERROR_GOTO(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_INTERNAL, SYS_DSNH4WREG_INDEX_FOR_TWAMP_UPD_CHKSUM, &dsnh), ret, end_0);

end_0:
    SYS_NH_UNLOCK;
    return ret;
}

int32
sys_usw_nh_set_ts_edit_en(uint8 lchip, uint32 nhid, uint8 ts_edit_en)
{
    int32 ret = CTC_E_NONE;
    sys_nh_info_com_t* p_nh_com_info = NULL;
    uint32 cmd = 0;
    DsNextHop8W_m ds_nexthop;


    SYS_NH_INIT_CHECK;
    if (!(DRV_IS_TMM(lchip) || DRV_IS_TMG(lchip)))
    {
        return  CTC_E_NOT_SUPPORT;
    }
    SYS_NH_LOCK;
    CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo_by_nhid(lchip, nhid, (sys_nh_info_com_t**)&p_nh_com_info), ret, done);
    if (!CTC_FLAG_ISSET(p_nh_com_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
    {
        ret = CTC_E_NOT_SUPPORT;
        goto done;
    }
    if (CTC_FLAG_ISSET(p_nh_com_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_TS_EDIT))
    {
        goto done;
    }
    cmd = DRV_IOR(DsNextHop8W_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, p_nh_com_info->hdr.dsnh_offset, cmd, &ds_nexthop);
    SetDsNextHop8W(V, tsEditMode_f,      &ds_nexthop,   (ts_edit_en?1:0));
    cmd = DRV_IOW(DsNextHop8W_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, p_nh_com_info->hdr.dsnh_offset, cmd, &ds_nexthop);
    CTC_SET_FLAG(p_nh_com_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_TS_EDIT);

done:
    SYS_NH_UNLOCK;
    return ret;
}


int32
sys_usw_nh_get_dsmet_end_offset(uint8 lchip, uint32* met_entry_ptr)
{
    SYS_NH_INIT_CHECK;
    *met_entry_ptr = SYS_NH_MET_END_REPLICATE_OFFSET;
    return CTC_E_NONE;
}

int32
sys_usw_nh_set_efd_redirect_nh(uint8 lchip, uint32 nh_id)
{
    SYS_NH_LOCK;
    g_usw_nh_master[lchip]->efd_nh_id = nh_id;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_MASTER, 1);
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_efd_redirect_nh(uint8 lchip, uint32* p_nh_id)
{
    SYS_NH_LOCK;
    *p_nh_id = g_usw_nh_master[lchip]->efd_nh_id;
    SYS_NH_UNLOCK;

    return CTC_E_NONE;
}

#define __NSH_API__

int32
sys_usw_nh_add_nsh_edit(uint8 lchip, uint16 nsh_id, ctc_nh_nsh_param_t* nsh_info)
{
    uint32 stats_ptr = 0;
    if (!MCHIP_NH(lchip)->add_nsh_id)
    {
        return CTC_E_NOT_SUPPORT;
    }
    CTC_PTR_VALID_CHECK(nsh_info);
    CTC_MAX_VALUE_CHECK(nsh_info->ttl, 63);
    CTC_MAX_VALUE_CHECK(nsh_info->spi, 0xFFFFFF);
    CTC_MAX_VALUE_CHECK(nsh_info->edit_offset, g_usw_nh_master[lchip]->nsh_edit_num - 1);
    CTC_MAX_VALUE_CHECK((nsh_info->ch_len), CTC_NH_NSH_CH_LEN);
    if (0 != ((nsh_info->ch_len) & 0x3))
    {
        return CTC_E_INVALID_PARAM;
    }
    if (nsh_info->stats_id)
    {
        CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip, nsh_info->stats_id, &stats_ptr));
    }
    if ((SYS_NH_NSH_UPDATE_ID) == nsh_id || (SYS_NH_NSH_REMOVE_ID) == nsh_id)
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "nsh_id (%u) is reserved!\n", nsh_id);
        return CTC_E_INVALID_PARAM;
    }

    if (MCHIP_NH(lchip)->add_nsh_id)
    {
        SYS_NH_LOCK;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_NSH, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(MCHIP_NH(lchip)->add_nsh_id(lchip, nsh_id, nsh_info, stats_ptr, 0), p_usw_nh_api_master[lchip]->p_mutex);
        SYS_NH_UNLOCK;
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_update_nsh_edit(uint8 lchip, uint16 nsh_id, ctc_nh_nsh_param_t* nsh_info)
{
    uint32 stats_ptr = 0;
    if (!MCHIP_NH(lchip)->update_nsh_id)
    {
        return CTC_E_NOT_SUPPORT;
    }
    CTC_PTR_VALID_CHECK(nsh_info);
    CTC_MAX_VALUE_CHECK(nsh_info->ttl, 63);
    CTC_MAX_VALUE_CHECK(nsh_info->spi, 0xFFFFFF);
    CTC_MAX_VALUE_CHECK((nsh_info->ch_len), CTC_NH_NSH_CH_LEN);
    if (0 != ((nsh_info->ch_len) & 0x3))
    {
        return CTC_E_INVALID_PARAM;
    }
    if (nsh_info->stats_id)
    {
        CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip, nsh_info->stats_id, &stats_ptr));
    }

    if (MCHIP_NH(lchip)->update_nsh_id)
    {
        SYS_NH_LOCK;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_NSH, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(MCHIP_NH(lchip)->update_nsh_id(lchip, nsh_id, nsh_info, stats_ptr), p_usw_nh_api_master[lchip]->p_mutex);
        SYS_NH_UNLOCK;
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_remove_nsh_edit(uint8 lchip, uint16 nsh_id)
{
    if (!MCHIP_NH(lchip)->remove_nsh_id)
    {
        return CTC_E_NOT_SUPPORT;
    }
    if ((SYS_NH_NSH_UPDATE_ID) == (nsh_id) || (SYS_NH_NSH_REMOVE_ID) == (nsh_id))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "nsh_id (%u) is reserved!\n", nsh_id);
        return CTC_E_INVALID_PARAM;
    }

    if (MCHIP_NH(lchip)->remove_nsh_id)
    {
        SYS_NH_LOCK;
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_NEXTHOP, SYS_WB_APPID_NH_SUBID_NSH, 1);
        CTC_ERROR_RETURN_WITH_UNLOCK(MCHIP_NH(lchip)->remove_nsh_id(lchip, nsh_id), p_usw_nh_api_master[lchip]->p_mutex);
        SYS_NH_UNLOCK;
    }

    return CTC_E_NONE;
}

int32
sys_usw_nh_get_nsh_edit_info(uint8 lchip, uint16 nsh_id, sys_nh_nsh_edit_info_t* p_nsh_edit)
{
    if (!MCHIP_NH(lchip)->get_nsh_edit_info)
    {
        return CTC_E_NOT_SUPPORT;
    }
    CTC_PTR_VALID_CHECK(p_nsh_edit);
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    if (MCHIP_NH(lchip)->get_nsh_edit_info)
    {
        SYS_NH_LOCK;
        CTC_ERROR_RETURN_WITH_UNLOCK(MCHIP_NH(lchip)->get_nsh_edit_info(lchip, nsh_id, p_nsh_edit), p_usw_nh_api_master[lchip]->p_mutex);
        SYS_NH_UNLOCK;
    }
    return CTC_E_NONE;
}


int32
sys_usw_nh_ecmp_get_lb_hash_mem_api(uint8 lchip, uint32 ecmp_nh_id, uint16 hash_value, uint32 * p_nh_id)
{
    int32 ret = CTC_E_NONE;
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_nh_id);
    SYS_NH_LOCK;
    ret = sys_usw_nh_ecmp_get_lb_hash_mem(lchip, ecmp_nh_id, hash_value, p_nh_id);
    SYS_NH_UNLOCK;
    return ret;
}
int32
sys_usw_nh_get_bind_ldp_en(uint8 lchip, uint8* enable)
{
    int32 ret = CTC_E_NONE;
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(enable);
    SYS_NH_LOCK;
    *enable = g_usw_nh_master[lchip]->bind_ldp ? 1:0;
    SYS_NH_UNLOCK;
    return ret;
}

int32
sys_usw_nh_set_logic_port_type(uint8 lchip, uint32 logic_port, void* p_value, uint8 in_cb)
{
    int32 ret = CTC_E_NONE;
    DsEgressLogicDestPort_m dst_prop;
    uint32 offset = 0;
    uint32 cmd = 0;
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_value);
    if (!in_cb)
    {
        SYS_NH_LOCK;
    }
    cmd = DRV_IOR(DsEgressLogicDestPort_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, logic_port, cmd, &dst_prop), ret, roll_back_0);
    CTC_ERROR_GOTO(sys_usw_nh_map_logic_dest_port(lchip, (sys_ldp_t*)p_value, (void*)&dst_prop, &offset), ret, roll_back_0);
    cmd = DRV_IOW(DsEgressLogicDestPort_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, logic_port, cmd, &dst_prop), ret, roll_back_0);
roll_back_0:
    if (!in_cb)
    {
        SYS_NH_UNLOCK;
    }
    return ret;
}
uint8
sys_usw_nh_get_vxlan_mode(uint8 lchip)
{
    return g_usw_nh_master[lchip]->vxlan_mode;
}

int32
sys_usw_nh_get_logic_port_type(uint8 lchip, uint32 logic_port, void* p_value, uint8 in_cb)
{
    int32 ret = CTC_E_NONE;
    DsEgressLogicDestPort_m dst_prop;
    uint32 offset = 0;
    uint32 cmd = 0;
    SYS_NH_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_value);
    if (!in_cb)
    {
        SYS_NH_LOCK;
    }
    cmd = DRV_IOR(DsEgressLogicDestPort_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, logic_port, cmd, &dst_prop), ret, roll_back_0);
    CTC_ERROR_GOTO(sys_usw_nh_unmap_logic_dest_port(lchip, (sys_ldp_t*)p_value, (void*)&dst_prop, &offset), ret, roll_back_0);

roll_back_0:
    if (!in_cb)
    {
        SYS_NH_UNLOCK;
    }
    return ret;
}

int32
sys_usw_nh_remove_mcast_all_members_api(uint8 lchip,  uint32 nhid)
{
    int32 ret = CTC_E_NONE;

    SYS_NH_LOCK;
    ret = sys_usw_nh_remove_mcast_all_members(lchip, nhid);
    SYS_NH_UNLOCK;

    return ret;
}

int32
sys_usw_nh_replace_mcast_members_api(uint8 lchip, uint32 nhid, ctc_mcast_nh_param_member_t* mem_array, uint32 mem_num)
{
    int32 ret = CTC_E_NONE;

    SYS_NH_LOCK;
    ret = sys_usw_nh_replace_mcast_members(lchip, nhid,mem_array,mem_num);
    SYS_NH_UNLOCK;

    return ret;

}

